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 4 and 3 and type the answer here:
  • Post
  • If I ever use code that might look like this:

    myobject.GetProperty("Address"),

    it's because I most likely will do something like this:

    string prop=ds.Tables[table].Rows[0][field].ToString();

    string dynamicValue=myobject.GetProperty(prop);

    I may have some scripting code in my database and it will determine the property to get.  This is dynamic.

  • To retake the question of Anwer Matter, there could be some scenari where it may be nice to generate dynamically a type, declaring methods and events, and then creating instances of that "type" (of course these instances would be of type dynamic.

    Here is an example :

       dynamic person = new ExpandoObject();

       //1. Define properties

       person.Name = "";

       person.FirstName = "";

       //2. Define instance methods

       person.ToString = new Func<string>(() => person.Name + " " + person.FirstName );

       //3. Define an event

       person.MyEvent = null;

       person.OnMyEvent = new Action<EventArgs>((e) =>

       {

           if (person.MyEvent != null)

               person.MyEvent (person, e);

       });

    We may not know the properties to use in some methods until runtime and that would be great to be able to use after instance of this "type person" to create new objects. Or at worse to "clone" this instance to use it after.

    Is there any way to do that ?

    Kind regards,

  • Pierre,

    There are various ways to do things like that. What you are describing sounds like a prototype language. The canonical (and easiest) way to do it would be to have a constructor function:

    dynamic CreatePerson() { // supply args here if desired

      dynamic person = new ExpandoObject();

      //1. Define properties

      person.Name = "";

      person.FirstName = "";

      //2. Define instance methods

      person.ToString = new Func<string>(() => person.Name + " " + person.FirstName );

      //3. Define an event

      person.MyEvent = null;

      person.OnMyEvent = new Action<EventArgs>((e) =>

      {

          if (person.MyEvent != null)

              person.MyEvent (person, e);

      });

       return person;

    }

    You could also make something that cloned an ExpandoObject. It’s a little bit tricky (you have to rebind delegates), but it should be doable.

  • Maybe I'm missing something.

    I don't see how this makes code easier to Maintain and Understand.  This seems like a step backwards.

    Please be kind in your response, I'm just looking for how this makes the final (developed) product better.

    Thx

  • Can you still call C# a type-specific language with the introduction of the dynamic type?  Wasn't that the whole point, catch your errors at compile time and not run-time?  VB has done this very same functionality for years, including type conversion without casting.  Is an attempt to bring the two languages closer together?

  • Dynamic in C# is primarily to enable C# programs to interoperate better with API's and object models defined in dynamic languages, without which you would be force to write very difficult to understand code, where the meaning gets lost in the mechanics.

  • it is great  I have gone through all this conversation and found it very usefull. thanks

  • I find that since C# 2.0, it's no more a real programing language but a experimental binding language.

    All new features since 2.0 are the answer to the ORM needs. For me,  LINQ and dynamic object should

    be in "Microsoft ORM framework". Not in C#. C# was pretty clean as a language. Able to compete with

    c++. Now it become a joke.

  • I agree with the general sentiment of the latter half of respondents. This seems to be a step backwards to late binding days to me. I may be a bit short-sited on this, and may be able to be persuaded of its use in very specific cirumstances, but the need for this level of dynamic coding seems to point to a problem in solution design. I am all for Agility, but this leaves too much room for problems with scalability and capacity planning.

  • I've a post here to examine the ExpandoObject itself is implemented. To make this clear, let us consider a MyExpando class, a minimal implementation of ExpandoObject.

    I'm inheriting MyExpando class from the DynamicObject, and these are the major methods we are overriding.

    TrySetMember- Provides the implementation of setting a member.

    TryGetMember-Provides the implementation of getting a member.

    TryInvokeMember- Provides the implementation of calling a member.

    GetDynamicMemberNames- Returns the enumeration of all dynamic member names.

    http://amazedsaint.blogspot.com/2009/09/systemdynamicexpandoobject-similar.html

  • Wouldnt this be a dangerous thing for security?

    I can imagine scenarios where someone passes in an expando object in a method that expects certain objects. The syntax will be alright sice its dynamic but I can imagine the whole system crashes at runtime.

    So isnt this a problem when using remoting for example?

  • Very interesting. This should clean up areas where I'm dealing with REST services (no strong names)

  • With great power comes great responsibility. Corollary -> With great flexibility comes great room for erroneous behavior.

    dynamic seems like a Pandora's box to me.

  • @Mast10

    I think you misunderstand the concept a little bit. You actually can't pass ExpandoObject to a method that expects a certain type.

    Let's consider this example:

    static void Main(string[] args)

    {

       dynamic test = new ExpandoObject();

       Sample(test);

    }

    static void Sample(IEnumerable<String> arg)

    {

       Console.WriteLine("Got there");

    }

    This will compile, but Sample(test); will throw an exception at run time. It will tell you that there is no necessary overload of the Sample() method. Note that you will never get into the Sample method itself. All the problems will be in the code where you create and operate with dynamic objects, but not in some method that expects a certain type of object.

    The only way to get into Sample method for a dynamic object is to be of the requested type. For example, the following works fine:

    dynamic test = new List<String>();

    Sample(test);

    It works, because when we call the method, "test" has the requested type.

    Now, where can you pass ExpandoObject to? Well, in any method that accepts parameters of type "object", "dynamic", or "ExpandoObject". But if method accepts parameters like "object" and "dynamic", it should be ready that it can get anything and act accordingly. I don't think that passing a dynamic object to a method that expects "object" should crash any well-written system, becuase it should be performing all type-checking already.

  • To maintain control over strong typing for frameworks and libraries, team build environments should prohibit "using System.Dynamic".

    Is anyone here (eg. Stephane) trying to tell me that C++ pointers are any less of a problem when utilized by sloppy developers?!

Page 3 of 5 (73 items) 12345