Differences Between Expandoobject, Dynamicobject and Dynamic

Differences between ExpandoObject, DynamicObject and dynamic

The dynamic keyword is used to declare variables that should be late-bound.

If you want to use late binding, for any real or imagined type, you use the dynamic keyword and the compiler does the rest.

When you use the dynamic keyword to interact with a normal instance, the DLR performs late-bound calls to the instance's normal methods.

The IDynamicMetaObjectProvider interface allows a class to take control of its late-bound behavior.

When you use the dynamic keyword to interact with an IDynamicMetaObjectProvider implementation, the DLR calls the IDynamicMetaObjectProvider methods and the object itself decides what to do.

The ExpandoObject and DynamicObject classes are implementations of IDynamicMetaObjectProvider.

ExpandoObject is a simple class which allows you to add members to an instance and use them dynamically.

DynamicObject is a more advanced implementation which can be inherited to easily provide customized behavior.

C# 4.0 Dynamic vs Expando... where do they fit?

Expando is a dynamic type to which members can be added (or removed) at runtime. dynamic is designed to allow .NET to interoperate with types when interfacing with dynamic typing languages such as Python and JavaScript.

So, if you need to handle a dynamic type: use dynamic and if you need to handle dynamic data such as XML or JSON: use ExpandoObject

The declaration of an expando shows the relationship between dynamic and the expando:

dynamic expando = new ExpandoObject();

And the ability to add a new property:

expando.SomeNewStringVal = "Hello World!";

That last line of code creates a brand new string property in the expando object called SomeNewStringVal. The string type is inferred from the assignment.

So an expando is a dynamic data type that can represent dynamically changing data. That's it in a nutshell. Here's a deeper look at dynamic and expando.

Complete example:

using System;
using System.Dynamic;

class Program
{
static void Main(string[] args)
{
dynamic expando = new ExpandoObject();
expando.SomeNewStringVal = "Hello Brave New Whirrled!";
Console.WriteLine(expando.SomeNewStringVal);

// more expando coolness/weirdness:
var p = expando as IDictionary<String, object>;
p["A"] = "New val 1";
p["B"] = "New val 2";

Console.WriteLine(expando.A);
Console.WriteLine(expando.B);
}
}

How do I detect an ExpandoObject vs a Dynamic Object?

The ExpandoObject can be casted to a dictionary to get the member names and values

public static bool IsExpandoObject(object objectValue)
{
if (objectValue == null)
return false;

if (IsDynamicObject(objectValue.GetType()))
{
IDictionary<string, object> expandoPropertyValues = objectValue as IDictionary<string, object>;
return expandoPropertyValues != null;
}

return false;
}

public static bool IsDynamicObject(Type type)
{
return typeof(IDynamicMetaObjectProvider).IsAssignableFrom(type);
}

When/Why should I use late-binding? (DynamicObject and ExpandoObject)

Most of the times it's better to stay away from using dynamic and adhere to
a type-safe programming style.

But there are situations when using dynamic could make your life better, or even more, could allow you to do really cool stuff that would be impossible to do without dynamic.

ExpandoObject

Consider the following example (without using ExpandoObject):

Dictionary<String, object> info = new Dictionary<string, object>();
Dictionary<String, object> person = new Dictionary<string,object>();
info["Person"] = person;
person["Name"] = "John";
person["Surname"] = "Smith";

Now using ExpandoObject:

dynamic info = new ExpandoObject();
info.Person = new ExpandoObject();
info.Person.Name = "John";
info.Person.Surname = "Smith";

Isn't this better? You could use ExpandoObject instead of dictionary whenever you need some kind of property bag to manipulate big hierarchies of objects. But if you have a plain small dictionary, probably, it's better to stick to the dictionary - it's clearer and there is no performance overhead.

DynamicObject

Now imagine that you have huge hierarchy of objects (say, coming from JSON).
You could create custom DynamicObject to deserialize JSON into dynamic object easily, see example here.
You can do a lot of more cool things via DynamicObject!


Plus, DLR (and dynamic support in C#) allows you, for example, to execute dynamic languages (e.g.IronRuby) from C# context.

As you see, dynamic support in C# is a very powerful concept, but must be used only whenever appropriate.

DynamicObject and TrySetMember performance vs ExpandoObject performance

First, you shouldn't measure time like this. DateTime.Now is not precise down to milliseconds. You should use Stopwatch for this.

Second, in .Net in general, and when dealing with dynamic especially, order matters. That's because there are several things the CLR and DLR have to compute the first time around, but can retrieve from cache the second time around.

Third, in my testing, I certainly did not see 750 ms, or anything close to that.

If I run SuperExpando first, and do both tests twice, I get times like this:

SuperExpando: 50,7736 ms
EpandoObject: 27,786 ms
SuperExpando: 0,0285 ms
EpandoObject: 0,0373 ms

So, SuperExpando is slower and the difference can be significant, but it's only the first time. When you run the same code with the same type again, it's much faster.

What happens when we reverse the order?

EpandoObject: 33,3107 ms
SuperExpando: 43,7383 ms
EpandoObject: 0,0348 ms
SuperExpando: 0,0186 ms

SuperExpando is still slower, but the difference is now smaller. And again, the second run for both is faster by several orders of magnitude.

Comparing dynamic objects in C#

The Microsoft API's for dynamically invoking methods and propertys on arbitrary dynamic objects (IDynamicMetaObjectProvider) are not easy to use when you don't have the compiler's help. You can use Dynamitey (via nuget) to simplify this completely. It has a static function Dynamic.InvokeGet to call property's getters with just a target and a property name.

To get a list of properties of the dynamic object, there is a bit of a gotcha, as the dynamic object has to support it (if it's a DynamicObject that means implementing GetDynamicMemberNames, Expando supports it, but random IDynamicMetaObjectProvider may not and just return an empty list). Dynamitey has a method to simplifying getting those names as well, Dynamic.GetMemberNames.

Both of those two functions give you the basic tools necessary to compare many arbitrary dynamic objects via properties.

//using System.Dynamic;
//using Dynamitey;
//using System.Linq;

IEnumerable<string> list1 =Dynamic.GetMemberNames(obj1);
list1 = list1.OrderBy(m=>m);
IEnumerable<string> list2 =Dynamic.GetMemberNames(obj2);
list2 = list2.OrderBy(m=>m);

if(!list1.SequenceEqual(list2))
return false;

foreach(var memberName in list1){
if(!Dynamic.InvokeGet(obj1, memberName).Equals(Dynamic.InvokeGet(obj2,memberName))){
return false;
}
}
return true;

However, if they are just your own DynamicObject subclass then it'd be easier to just follow the typical rules for implementing Equals, there really is no difference from non-dynamic objects, and just compare what you are internally using for state.

can one convert a dynamic object to an ExpandoObject (c#)

Nope. A dynamic object doesn't enforce the type at compile time, but it doesn't magically make your object expandable (unless it's an ExpandoObject).

You can however, make some kind of wrapper or proxy using DynamicObject... something like:

public class ExpandedObjectFromApi : DynamicObject
{
private Dictionary<string, object> _customProperties = new Dictionary<string, object>();
private object _currentObject;

public ExpandedObjectFromApi(dynamic sealedObject)
{
_currentObject = sealedObject;
}

private PropertyInfo GetPropertyInfo(string propertyName)
{
return _currentObject.GetType().GetProperty(propertyName);
}

public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var prop = GetPropertyInfo(binder.Name);
if(prop != null)
{
result = prop.GetValue(_currentObject);
return true;
}
result = _customProperties[binder.Name];
return true;
}

public override bool TrySetMember(SetMemberBinder binder, object value)
{
var prop = GetPropertyInfo(binder.Name);
if(prop != null)
{
prop.SetValue(_currentObject, value);
return true;
}
if(_customProperties.ContainsKey(binder.Name))
_customProperties[binder.Name] = value;
else
_customProperties.Add(binder.Name, value);
return true;
}
}

And then you can use it like:

dynamic myExpandedObject = new ExpandedObjectFromApi(sealedObject);

This should return the original object properties if found, or if no property of that name is in the original object, it'll add it as a "custom" property.

I've made the code in the Stack Overflow editor and probably made a lot of mistakes, it's not suitable for copy/paste, and it needs tons of error checking (also needs to implement fields and methods, if the received object has them). Just wrote it so you get the basic idea.

You also may want to add a special property (something called WrappedObject, for example) and capture it in TryGetMember, so you can get the original object back.



Related Topics



Leave a reply



Submit