HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpCritical

What are the true benefits of ExpandoObject?

Submitted by: @import:stackoverflow-api··
0
Viewed 0 times
benefitsarewhattheexpandoobjecttrue

Problem

The ExpandoObject class being added to .NET 4 allows you to arbitrarily set properties onto an object at runtime.

Are there any advantages to this over using a Dictionary, or really even a Hashtable? As far as I can tell, this is nothing but a hash table that you can access with slightly more succinct syntax.

For example, why is this:

dynamic obj = new ExpandoObject();
obj.MyInt = 3;
obj.MyString = "Foo";
Console.WriteLine(obj.MyString);


Really better, or substantially different, than:

var obj = new Dictionary();
obj["MyInt"] = 3;
obj["MyString"] = "Foo";

Console.WriteLine(obj["MyString"]);


What real advantages are gained by using ExpandoObject instead of just using an arbitrary dictionary type, other than not being obvious that you're using a type that's going to be determined at runtime.

Solution

Since I wrote the MSDN article you are referring to, I guess I have to answer this one.

First, I anticipated this question and that's why I wrote a blog post that shows a more or less real use case for ExpandoObject: Dynamic in C# 4.0: Introducing the ExpandoObject.

Shortly, ExpandoObject can help you create complex hierarchical objects. For example, imagine that you have a dictionary within a dictionary:

Dictionary dict = new Dictionary();
Dictionary address = new Dictionary();
dict["Address"] = address;
address["State"] = "WA";
Console.WriteLine(((Dictionary)dict["Address"])["State"]);


The deeper the hierarchy, the uglier the code. With ExpandoObject, it stays elegant and readable.

dynamic expando = new ExpandoObject();
expando.Address = new ExpandoObject();
expando.Address.State = "WA";
Console.WriteLine(expando.Address.State);


Second, as was already pointed out, ExpandoObject implements INotifyPropertyChanged interface which gives you more control over properties than a dictionary.

Finally, you can add events to ExpandoObject like here:

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;

       e?.Invoke(d, new EventArgs());
   }

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


Also, keep in mind that nothing is preventing you from accepting event arguments in a dynamic way. In other words, instead of using EventHandler, you can use EventHandler which would cause the second argument of the handler to be dynamic.

Code Snippets

Dictionary<String, object> dict = new Dictionary<string, object>();
Dictionary<String, object> address = new Dictionary<string,object>();
dict["Address"] = address;
address["State"] = "WA";
Console.WriteLine(((Dictionary<string,object>)dict["Address"])["State"]);
dynamic expando = new ExpandoObject();
expando.Address = new ExpandoObject();
expando.Address.State = "WA";
Console.WriteLine(expando.Address.State);
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;

       e?.Invoke(d, new EventArgs());
   }

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

Context

Stack Overflow Q#1653046, score: 786

Revisions (0)

No revisions yet.