Invoke a member of a dynamic object with a name defined at runtime in a String
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"));