Go-Go-Gadget ExpandoObject!

I talked a little bit about the new “dynamic” objects coming in C# 4.0, basically in the context of COM Interop, but here’s a refresher.

Instead of:

1
2
object comObject = GetComObjectFromSomeSource();
Console.WriteLine(comObject.GetProperty("Address"));

you can now go

1
2
dynamic dynaObject = GetComObjectFromSomeSource();
Console.WriteLine(dynaObject.Address);

Which is pretty neat in itself, as it’ll support Intellisense and all that fun stuff. To add to this, I just read about “ExpandoObjects”, which is a new class in new the “Dynamic Language Runtime”. Basically, an ExpandoObject is an easy way to create an object with whatever properties you need on the fly. Let’s do an example in the context of an XML node.

Old Way
1
2
3
4
5
6
7
8
9
10
11
XElement contactXML =
    new XElement("Contact",
        new XElement("Name", "Patrick Hines"),
        new XElement("Phone", "206-555-0144"),
        new XElement("Address",
            new XElement("Street1", "123 Main St"),
            new XElement("City", "Mercer Island"),
            new XElement("State", "WA"),
            new XElement("Postal", "68042")
        )
    );
New Way
1
2
3
4
5
6
7
8
dynamic contact = new ExpandoObject();
contact.Name = "Patrick Hines";
contact.Phone = "206-555-0144";
contact.Address = new ExpandoObject();
contact.Address.Street = "123 Main St";
contact.Address.City = "Mercer Island";
contact.Address.State = "WA";
contact.Address.Postal = "68402";

As you can see, we’ve instantiated an ExpandoObject (but as a dynamic object), and are basically declaring and setting properties on it as we need to. Also, to declare our sub-nodes (i.e. Address), we do the same thing and just set it as a property on the parent node. Not only is this a little cleaner to code, but all the properties you declare carry forward with the object. So now instead of this:

1
2
Console.WriteLine((string)contactXML
  .Element("Address").Element("State"));

We can do this:

1
Console.WriteLine(contact.Address.State);

So that’s all fine and dandy, and works great for certain implementations (i.e. Data Transport Objects like the example). But what happens when you want a little more control over what happens within the ExpandoObject? That’s where DynamicObject comes in. DynamicObject is the base class that ExpandoObject extends, and allows you to override methods that are called whenever someone uses the object. By overriding methods like TryGetMember, TrySetMember, TryInvoke, etc., you can control exactly what happens within the dynamic object. Here’s a quick example of overriding the TryGetMember method.

Custom Dynamic Object
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UselessGetObject : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder,
      out object result)
    {
        //just return the name of the property they tried to get
        result = binder.Name;
        return true;
    }
}
//usage
dynamic uselessObject = new UselessGetObject();
Console.WriteLine(uselessObject.SomeRandomPropertyName);
//this will output "SomeRandomPropertyName";

Of course to make any sort of useful Dynamic Object there’s a lot more involved, like managing the creation and recall of properties, handing conversions, invoking methods, etc. Which is why they provided ExpandoObject as a quick “I only need properties” alternative. But if you wanted to create a dynamic wrapper class, let’s say for an XML Document, you easily could do so using this new DynamicObject base class.

Comments