read and write properties on dynamic objects in .NET/C#

Ok, the headline sounds a little bit funny, because first of all, dynamic objects have no properties. Also you can not use reflection on a dynamic type, because it’s dynamic. What I actually want to do, is to access values of a dynamic object by its name – but I don’t know the name of the property on compile time, but during execution.

I want to do something like that:

dynamic obj = GetDynamicObject();
string myPropertyValue = DynamicExtension.GetValue(obj, "MyProperty");
DynamicExtension.SetValue(obj, "MyProperty", "some cool value");

So how can we do this? Reflection is not possible, and not all dynamic types impement IDictionary like ExpandoObject.

But how can we achieve this? By looking at the disassembled code, of a dynamic class, and the way it is accessed, we can find out, how we can access it ourself…

dynamic dynObj = new TestClass
{
  TestProperty = "Hello World",
  TestInt = 20
};
var val = dynObj.TestProperty;
dynObj.TestProperty = "Hello C#";

Because I don’t want to flood this post, I just copied the essentials from the IL. Basically there are 2 parts:
1. create a Binder
2. create a CallSite to execute the getter/setter.

// the getter
            var binder = Binder.GetMember(
                CSharpBinderFlags.None,
                "TestProperty",
                typeof(object),
                new CSharpArgumentInfo[] { 

 CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.NamedArgument, null)
                });

            var getter = CallSite<Func<CallSite,object,object>>.Create(binder);
            var val = getter.Target(getter,  dynObj);

// the setter
var setterBinder = Binder.SetMember(
    CSharpBinderFlags.None,
    "TestProperty",
    typeof(object),
    new CSharpArgumentInfo[] {
        CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
        CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null) });
// the IL actually uses string as value type, but we use object here, to be more flexible
var setter = CallSite<Func<CallSite,object,object,object>>.Create(setterBinder);
setter.Target(setter, dynObj, "Hello C#");

So now just wrap it up to our two functions:

    public static class DynamicHelper
    {
        public static object GetValue(object obj, string name)
        {
            var binder = Binder.GetMember(
                        CSharpBinderFlags.None,
                        name,
                        typeof(object),
                        new CSharpArgumentInfo[] {
                            CSharpArgumentInfo.Create(
                                CSharpArgumentInfoFlags.NamedArgument,
                                null)
                        });

            var getter = CallSite<Func<CallSite,object,object>>.Create(binder);
            return getter.Target(getter, obj);
        }

        public static void SetValue(object obj, string name, object value)
        {
            var setterBinder = Binder.SetMember(
                CSharpBinderFlags.None,
                name,
                typeof(object),
                new CSharpArgumentInfo[] {
                  CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
                  CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null) });
            // the IL actually uses string as value type, but we use object here, to be more dynamic
            var setter = CallSite<Func<CallSite,object,object,object>>.Create(setterBinder);
            setter.Target(setter, obj, value);
        }
    }

1 thought on “read and write properties on dynamic objects in .NET/C#

  1. Pingback: Copy an entire synced Realm | kison.info

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.