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 Comment on “read and write properties on dynamic objects in .NET/C#”