Dynamic in C# 4.0: Introducing the ExpandoObject

Dynamic in C# 4.0: Introducing the ExpandoObject

Rate This
  • Comments 73

You have probably already heard about the new dynamic feature in C# 4.0 and how it is used to support COM interop. If you haven't, I strongly recommend reading the following MSDN articles: Using Type dynamic and How to: Access Office Interop Objects by Using Visual C# 2010 Features.

Well, where else can you use this new feature? What are the use cases? Where does dynamic dispatch work better than static typing?

The quick answer is that whenever you see syntax like myobject.GetProperty("Address"), you have a use case for dynamic objects. First of all, the above syntax is difficult to read. Second, you don’t have any IntelliSense support for the property name, and if the “Address” property doesn’t exist you get a run-time exception. So why not create a dynamic object that calls the property as myobject.Address? You still get the run-time exception, and you still don't get IntelliSense, but at least the syntax is much better.

In fact, it’s not just better syntax. You also get flexibility. To demonstrate this flexibility, let’s move to ExpandoObject, which is a part of the new dynamic language runtime (DLR). ExpandoObject instances can add and remove members at run time. Where can you use such an object? XML is a good candidate here.

Here’s a code example that I took from MSDN. (Yes, I am an MSDN writer myself, so I use MSDN a lot.)

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")
        )
    );

Although LINQ to XML is a good technology and I really love it, those new XElement parts look a little bit annoying. This is how I can rewrite it by using ExpandoObject.

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";

Just note a couple of things. First, look at the declaration of contact.

dynamic contact = new ExpandoObject();

I didn’t write ExpandoObject contact = new ExpandoObject(), because if I did contact would be a statically-typed object of the ExpandoObject type. And of course, statically-typed variables cannot add members at run time. So I used the new dynamic keyword instead of a type declaration, and since ExpandoObject supports dynamic operations, the code works.

Second, notice that every time I needed a node to have subnodes, I simply created a new instance of ExpandoObject as a member of the contact object.

It looks like the ExpandoObject example has more code, but it’s actually easier to read. You can clearly see what subnodes each node contains, and you don’t need to deal with the parentheses and indentation. But the best part is how you can access the elements now.

This is the code you need to print the State field in LINQ to XML.

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

And this is how it looks with ExpandoObject.

Console.WriteLine(contact.Address.State);

But what if you want to have several Contact nodes? Like in the following LINQ to XML example.

XElement contactsXML =
    new XElement("Contacts",
        new XElement("Contact",
            new XElement("Name", "Patrick Hines"),
            new XElement("Phone", "206-555-0144")
        ),
        new XElement("Contact",
            new XElement("Name", "Ellen Adams"),
            new XElement("Phone", "206-555-0155")
        )
    );

Just use a collection of dynamic objects.

dynamic contacts = new List<dynamic>();

contacts.Add(new ExpandoObject());
contacts[0].Name = "Patrick Hines";
contacts[0].Phone = "206-555-0144";

contacts.Add(new ExpandoObject());
contacts[1].Name = "Ellen Adams";
contacts[1].Phone = "206-555-0155";

Technically speaking, I could write dynamic contacts = new List<ExpandoObject>() and the example would work. However, there are some situations where this could cause problems, because the actual type of the list elements should be dynamic and not ExpandoObject, and these are two different types. (Once again, references to the ExpandoObject objects are statically-typed and do not support dynamic operations.)

Now, if you want to find all the names in your contact list, just iterate over the collection.

foreach (var c in contacts)
    Console.WriteLine(c.Name);

Again, this syntax is better than LINQ to XML version.

foreach (var c in contactsXML.Descendants("Name"))
    Console.WriteLine((string)c);

So far, so good. But one of the main advantages of LINQ to XML is, well, LINQ. How would you query dynamic objects? Although there is still a lot to be done in this particular area, you can query dynamic objects. For example, let’s find all the phone numbers for the specified name.

var phones = from c in (contacts as List<dynamic>)
             where c.Name == "Patrick Hines"
             select c.Phone;

True, the cast here doesn’t look like something strictly necessary. Certainly the compiler could have determined at run-time that contacts is List<dynamic>. But as I said, there is still some work to be done in this area.

Another thing to note is that this trick works only for the LINQ to Objects provider. To use dynamic objects in LINQ to SQL or other LINQ providers, you need to modify the providers themselves, and that’s a completely different story.

However, even with the cast, syntax is still better than in a LINQ to XML query.

var phonesXML = from c in contactsXML.Elements("Contact")
                where c.Element("Name").Value == "Patrick Hines"
                select c.Element("Phone").Value;

Sure, there are some things that look better in LINQ to XML. For example, if you want to delete a phone number for all the contacts, you can write just one line of code in LINQ to XML.

contactsXML.Elements("Contact").Elements("Phone").Remove();

Since C# doesn’t have syntax for removing object members, you don’t have an elegant solution here. But ExpandoObject implements IDictionary<String, Object> to maintain its list of members, and you can delete a member by deleting a key-value pair.

foreach (var person in contacts)
    ((IDictionary<String, Object>)person).Remove("Phone");

There are other useful methods in LINQ to XML like Save() and Load(). For ExpandoObject you need to write such methods yourself, but probably only once. Here, casting to the IDictionary interface can help as well.

And although I’ve been comparing LINQ to XML and ExpandoObject in this post, these two approaches are not “rivals”. You can convert ExpandoObject to XElement and vice versa. For example, this is what the ExpandoObject to XElement conversion might look like.

private static XElement expandoToXML(dynamic node, String nodeName)
{
    XElement xmlNode = new XElement(nodeName);

    foreach (var property in (IDictionary<String, Object>)node)
    {

        if (property.Value.GetType() == typeof(ExpandoObject))
            xmlNode.Add(expandoToXML(property.Value, property.Key));

        else
            if (property.Value.GetType() == typeof(List<dynamic>))
                foreach (var element in (List<dynamic>)property.Value)
                    xmlNode.Add(expandoToXML(element, property.Key));
            else
                xmlNode.Add(new XElement(property.Key, property.Value));
    }
    return xmlNode;
}

This little trick might help you access all the LINQ to XML functions when you need them but at the same time use more convenient syntax when creating and modifying XML trees.

Of course, XML is not the only area where you can use ExpandoObject. If you heavily use reflection or work a lot with script objects, you can simplify your code with ExpandoObject. On the other hand, ExpandoObject is not the only useful class that the DLR provides. The DynamicObject class, for example, enables you to take more control over dynamic operations and define what actually happens when you access a member or invoke a method. But that’s a topic for another blog post.

One more thing to note is that libraries that look up members by name might someday adopt the DLR and implement the IDynamicMetaObjectProvider interface. (This interface actually provides all the “magic” – or dynamic dispatch – for ExpandoObject and the dynamic feature in general.) For example, if LINQ to XML implements this interface, you would be able to write dynamic contacts = new XmlElement() instead of dynamic contacts = new ExpandoObject() and perform the same operations that I have shown in the examples for the ExpandoObject type.

All the examples provided in this blog post work in Visual Studio 2010 Beta 1. If you have any comments or suggestions, you are welcome to post them here or contact the DLR team at http://www.codeplex.com/dlr. You can also write an e-mail to the DLR team at dlr@microsoft.com.

Update:

See how you can improve this example in my next post: Dynamic in C# 4.0: Creating Wrappers with DynamicObject.

Leave a Comment
  • Please add 1 and 5 and type the answer here:
  • Post
  • For this use case, wouldn't it be neater to make a wrapper class that implements IDynamicMetaObjectProvider by directly forwarding into an XElement? That way there is no need to build up the structure in a hierarchy of ExpandoObjects and then later need to do a full recursive copy when you want an XElement tree - it would already be an XElement tree.

  • Why not just declare contacts as var or List<dynamic>? Does it need to be declared dynamic? Then it could be passed into LINQ contexts without casts.

    Also, it'd be nice to have syntax such as contacts.Add(new ExpandoObject() as dynamic { Name = "Eric" });

  • Niiice. I was wondering once upon a time if that would be possible. Thanks for sharing.

  • The dynamic enhancements to C# are bringing me back to the language. I've haven't been really excited about anything new in .Net since 2.0 - LINQ seemed (to me) to be a solution in search of a problem - but now I'm really looking forward to using 4.

    Since falling in love with dynamic languages like javascript, python and PHP I've felt like C# was really lagging behind. It looks like these new features will combine the best of both worlds: the power and maturity of the .Net framework and the flexibility and productivity of dynamic languages.

    Thank you!

  • Daniel,

    Implementing IDynamicMetaObjectProvider is a challenging task. And I wanted to provide a simple example that people can use right away. If LINQ to XML decides one day to support this type of syntax, they will probably need to implement this interface. But defenitely it's not a task for people who just use this library.

    By the way, ExpandoObject already implements IDynamicMetaObjectProvider. Otherwise none of those features would be possible.

    But you are right about the wrapper. For this particular example, it is actually a better way to do things. But instead of implementing IDynamicMetaObjectProvider, you can use the DynamicObject class (which, again, already implements this interface). I am planning another blog post about the DynamicObject class, where I'll show how you can do it.

    The idea of this blog post was to introduce the new dynamic features in an easy-to-understand and easy-to-try way. I hope that it is clear that ExpandoObject is not limited to XML. You can sometimes use it instead of anonymous types, for example.

  • Jason,

    Yes, it may help you to solve this particular problem wth cast. But if you declare contacts as List<dynamic> (or var, which is the same in this case) it could be initialized only with List<dynamic>. If you declare contacts as dynamic, you can initialize it with whatever you want, depending on your XML structure: single ExpandoObject, List<dynamic>, array, etc. The dynamic type allows you to be more flexible here.

  • This is pretty cool stuff.  In addition to dynamically generated properties, the ExpandoObject will also let you define runtime generated methods quite easily.  For example:

    public static void Main(string[] args)

           {

               dynamic dynamicXml = new ExpandoObject();

               dynamicXml.DoSomething = new Action<string>(s =>

               {

                   Console.WriteLine(s);

               });

               dynamicXml.DoSomething("Hello World!");

               Console.ReadLine();

           }

    I was also trying to figure out a way to create run-time generated events, but have so far been unsuccessful.  If anybody has any ideas on how to do that, I would be interested.

  • Chris,

    You are absolutely right about methods. I actually hoped someone would ask, but you found the solution yourself. This is exactly the way it is supposed to work.

    As for events, you cannot generate them at run-time for ExpandoObject, as far as I know. But I'll check it once again with the DLR team.

  • Hey, this is John from the DLR team. Here's an example of doing events on ExpandoObject:

    using System;

    using System.Dynamic;

    namespace ConsoleApplication2

    {

       class Program

       {

           static void Main(string[] args)

           {

               dynamic d = new ExpandoObject();

               // Initialize the event to null (meaning no handlers)

               d.MyEvent = null;

               // Add some handlers

               d.MyEvent += new EventHandler(OnMyEvent);

               d.MyEvent += new EventHandler(OnMyEvent2);

               // Fire the event

               EventHandler e = d.MyEvent;

               if (e != null)

               {

                   e(d, new EventArgs());

               }

               // We could also fire it with...

               //      d.MyEvent(d, new EventArgs());

               // ...if we knew for sure that the event is non-null.

           }

           static void OnMyEvent(object sender, EventArgs e)

           {

               Console.WriteLine("OnMyEvent fired by: {0}", sender);

           }

           static void OnMyEvent2(object sender, EventArgs e)

           {

               Console.WriteLine("OnMyEvent2 fired by: {0}", sender);

           }

       }

    }

  • I'm not too sure about using ExpandoObject in this case. Wouldn't it cause memory issues when using ExpandoObjects this way in a long running process? Because ExpandoObject caches "classes" and their transitions, it might keep a lot of information that doen't have much use later on in this scenario -- the cache is good when the structure of an "object" doesn't change often, but if it's used like a property bag that changes often, we might be better off falling back to go without caching.

    I thought inheriting from DynamicObject would do the jot better, since we can make a proprty bag impl backed up by a plain old dictionary, without all the caching.

  • @John: Your solution for events is far simpler than what I was trying to do.  I was trying to take advantage of events being a sugar for delegates, and therefore trying to dynamically build a delegate and assigning it to as a member of the dynamic object, and then assigning handlers.

  • Would it be possible to implement property deletion as something like "expando.Property = ExpandoObject.Removed"?

  • Sorry for the double-post, but now that I think of it, I think ExpandoObject.Remove(expando); would be better, or DynamicObject.Remove() if you wanted a consistent method of removing properties from dynamic objects.

  • The value of this feature is negligible, at least as long as Intellisense and strong type-checking is not supported (for now, it's just a dictionary in disguise...).

    I bet many of us would love to see the C# team focusing and spending its time on fixing issues that truly bother programmers, such as the lack of deterministic destruction (google for "lior eti deterministic destruction" for a good article on missing features that truly bother programmers, as well as a discussion with practical suggestions for implementing deterministic destruction in .NET)

  • Would it be possible to implement

    property/methods creation using string expression in a [ ] suffix :

    dynamic contact = new ExpandoObject();

    contact["Name"] = "Patrick Hines";?

Page 1 of 5 (73 items) 12345