I want to access a property on an object while leveraging the DLR binding mechanism.
dynamic
keyword in C#) because I do not know the property name at compile-time;IDictionary<string, object>
, to my knowledge, only solves the case of dynamic classes that choose to implement that interface (such as ExpandoObject
).Here is the demonstration code:
static void Main(string[] args)
{
dynamic obj = new System.Dynamic.ExpandoObject();
obj.Prop = "Value";
// C# dynamic binding.
Console.Out.WriteLine(obj.Prop);
// IDictionary<string, object>
Console.Out.WriteLine((obj as IDictionary<string, object>)["Prop"]);
// Attempt to use reflection.
PropertyInfo prop = obj.GetType().GetProperty("Prop");
Console.Out.WriteLine(prop.GetValue(obj, new object[] { }));
Console.In.ReadLine();
}
You can create custom dynamic objects by using the classes in the System. Dynamic namespace. For example, you can create an ExpandoObject and specify the members of that object at run time. You can also create your own type that inherits the DynamicObject class.
The dynamic language runtime (DLR) is an API that was introduced in . NET Framework 4. It provides the infrastructure that supports the dynamic type in C#, and also the implementation of dynamic programming languages such as IronPython and IronRuby.
The ExpandoObject class enables you to add and delete members of its instances at run time and also to set and get values of these members. This class supports dynamic binding, which enables you to use standard syntax like sampleObject. sampleMember instead of more complex syntax like sampleObject.
I was finally able to do it by using the C# runtime binder. (I believe it should be possible to do that with a simpler binder implementation, but I was unable to write a working one - probably writing a "simple" implementation is already quite tough).
using Microsoft.CSharp.RuntimeBinder;
private class TestClass
{
public String Prop { get; set; }
}
private static Func<object, object> BuildDynamicGetter(Type targetType, String propertyName)
{
var rootParam = Expression.Parameter(typeof(object));
var propBinder = Microsoft.CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None, propertyName, targetType, new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
DynamicExpression propGetExpression = Expression.Dynamic(propBinder, typeof(object),
Expression.Convert(rootParam, targetType));
Expression<Func<object, object>> getPropExpression = Expression.Lambda<Func<object, object>>(propGetExpression, rootParam);
return getPropExpression.Compile();
}
static void Main(string[] args)
{
dynamic root = new TestClass { Prop = "StatValue" };
Console.Out.WriteLine(root.Prop);
var dynGetter = BuildDynamicGetter(root.GetType(), "Prop");
Console.Out.WriteLine(dynGetter(root));
root = new System.Dynamic.ExpandoObject();
root.Prop = "ExpandoValue";
Console.WriteLine(BuildDynamicGetter(root.GetType(), "Prop").Invoke(root));
Console.Out.WriteLine(root.Prop);
Console.In.ReadLine();
}
Output:
StatValue
StatValue
ExpandoValue
ExpandoValue
The opensource framework dynamitey will do this (available via nuget). It uses that same api calls as the c# compiler.
Console.Out.WriteLine(Dynamic.InvokeGet(obj,"Prop"));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With