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 3 and 6 and type the answer here:
  • Post
  • Really looking forward to all this 2010/4.0 stuff.

  • I just like the name - 'ExpandoObject' - brilliant!

  • For those sniping at how 'real programmers' wouldn't use this, consider that expando objects and properties are widely used in Javascript and that the IE DOM supports them against any HTML element.

    This sort of functionality makes it much easier to interoperate with dynamic languages etc, and it also makes it easier to add functionality to an application such as an internal macro language for automation etc. It's just another tool, after all. Remember that Pascal was designed on the 'mummy knows best' principle and was rightly criticised for its limitations, enforced supposedly to ensure 'good programming practices'. Frankly, if I want to use a hammer to open a can of tuna, that's my prerogative, thank you very much.

  • As a professional, I have to agree that C# is taking some huge steps backwards.

    All this dynamic and ExpandoObjects stuff is making me laugh. We program everyday with C#, Javascript and PHP. The expando behavior in these languages is awful. In PHP it leads to a million runtime errors; in Javascript, it's a double edge sword because on one hand you love it for JSON and Ajax, but you hate it for the same reasons as you hate it for PHP.

    We already have a hard time training old timers who loved C and C++ that OOP with C# are safer bets for solid apps, and enough of a hard time training youngsters out of school who think anything looks like a nail. This is just opening the door to some serious code abuse.

    What this type of things does (dynamic and ExpandoObject) is make us add some more red text at the bottom of the "what not to use or get fired" section of our Code Conventions - next to LINQ and the var keyword.

    It would be nice if the C# team would focus more on performance than on features that vulgarize the language.

    Just watch the C# forums in 4 years from now, and we're going to see a ton of trash code everywhere.

    By the time, we're done with the "I told you so" and finger pointing, C# 5.0 will come around and break compatiblity with C# 4 and hopefully bring some sense back to the language.

    We use things like object.GetProperty("MyProp") everywhere, and guess what? Who cares about intellisense????? In the scenario with the GetProperty(), I  can search the code base and find all the places that use reflexion. With dynamic, not only will I not know 2 screens down from the definition line that I am looking at a dynamic object, but in addition, I just hid the code from the search audit team. Why would you want to do that??

    This is awful.

  • I find the fact that the object type 'dynamic' does not support dynamic operations. I am refering to the following statement from the above article," (Once again, references to the ExpandoObject objects are statically-typed and do not support dynamic operations.) "

    99% of everything I program is dynamically directed through user input or selection. All of my programming is web based and I do not deal with office apps so maybe there is where one would need a non-dynamic method of data manipulation. Can you give a quick explanation on why someone would give the name 'dynamic' to an object that does not support dynamic operations?

    Thanks,

    John P.

  • In your example:

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

    To create a "Location" with attributes you need to go:

    contacts[0].Location = new ExpandoObject();

    contacts[0].Location.Street = "StreetName1";

    and

    contacts[1].Location = new ExpandoObject();

    contacts[1].Location.Street = "StreetName2";

    Since intellisense and compilation errors are ignored regardless, why do you even need the:

    contacts[0].Location = new ExpandoObject();

    ?

    You could just go contacts[0].Location_Street = "StreetName1";

    Or the . values after Location should be dynamically created like the values of "Location" itself (EG: Streetname)

    Hope I made any sense ;p

    - Reelix

  • I've an ElasticObject implementation, that'll allow you to go with multiple levels of properites.. aka.

    dynamic obj=new ElasticObject();

    obj.Customer.Name.FirstName="Joe";

    obj.Customer.Age="30";

    And you can convert that directly to xml - amazedsaint.blogspot.com/.../introducing-elasticobject-for-net-40.html

  • I am in total agreement with the negative sentiments expressed in several comments, especially @bob's. Dynamic and ExpandoObject belong in the same dump as LINQ from the perspective of production quality high-performance code. I am no fan of using these cosmetic language constructs and features. As a professional developer, I find the name "ExpandoObject" itself insulting! I can very well imagine fat books appearing soon on how to "optimize" this nonsense. What is the net value of inventing such cosmetic constructs, and learning their optimal usage? As @bob says, who cares about intellisense or better syntax beyond a point? The author herself hardly makes a convincing case right at the outset: "You still get the run-time exception, and you still don't get IntelliSense, but at least the syntax is much better"! Really???

  • British reporters are known for doing almost anything to get a Mulberry Bags. But reports that a newspaper secretly listened to telephone messages of murdered schoolgirls and other private citizens have produced Mulberry Handbags and anger.

    On Friday, British police arrested Andy Coulson, former editor of Mulberry Bag Britain's best-selling newspaper, News of Mulberry Outlet the World. The investigation led him to Mulberry UK Sale resign in January as communications director to Prime Minister David Cameron.

    The arrest came in a widening investigation of Mulberry UK telephone hacking. Other accusations include paying police for mulberry shoulder bags information on stories. The Reuters news agency reported that Mr. Coulson was released on Mulberry Bag UK until a date in October.

    Prime Minister Cameron promised Men's Mulberry Bags Friday that a judge will lead a full public inquiry into Women's Mulberry Bags the case after police complete their investigation.

    DAVID CAMERON: "Murder victims, terrorist victims, families who have lost loved ones, sometimes defending our country, that these people could have had their phones hacked into, in order to generate stories for Mulberry Bags  Mulberry Handbags  Mulberry Bag   Mulberry Outlet  Mulberry UK  mulberry bayswater bag  Mulberry Alexa Bag, is simply disgusting."

  • hello..

    I am trying to dynamically create an XML file. I came across the ExpandoObject which seems to suit my goals. But when I have the List <dynamic>, i cannot do the expandoToXML conversion, in the procedure suggested above. I. e.

    [CODE]

    //---------------------------------------

    dynamic myXML = new List<dynamic>();

    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 (ExpandoObject)property.Value)

                       xmlNode.Add(expandoToXML(element, property.Key));

               else

                   xmlNode.Add(new XElement(property.Key, property.Value));

      }

      return xmlNode;

    }

    //---------------------------------------

    [/CODE]

    Though the code above seems to work, but not with the List.

    I try this:

    [CODE]

    for (int i=0; i<6; i++)

    {

    myXML.Add(new ExpandoObject());

    ImyXML[i].testProperty=Convert.ToString(i);

    }

     //--- conversion

    XElement temp = expandoToXML(myXML, "testing");

    [/CODE]

    I get the follwing error:

    Cannot vonvert type "System.Collection.Generic.List´1[System.Object] to type "System.Collection.Generic.Idictionary´2[System.String,System.Object]"

    ... any ideas? has anybody tried this?an error in my code?

  • To whomever is having trouble with "dynamic myXML = new List<dynamic>(); to XML",

    have a look at this example, it does exactly what your having trouble with. The author references and gives credit to this article:

    www.codeproject.com/.../dynamicincsharp.aspx

  • For those that can't find any practical use for Expando, i have something. They could use them as results in various linq to entity queries, when those are used just for display/reporting. The would remove the nessesity to create viewmodels for each view, or having to query for the entire entity for use in a plethora of screens.It's support for binding and with use of serialization could help a lot when there are sources with generic output.

    Regards.

  • As an aside it might be cleaner to read the code and use the `is` instead of comparing types:

    if (property.Value is ExpandoObject )

Page 5 of 5 (73 items) 12345