使用在运行时在String中定义的名称调用动态对象的成员

Jea*_*nal 8 .net dynamic-language-runtime

我想在利用DLR绑定机制的同时访问对象上的属性.

  • 我不能使用本机绑定机制(dynamicC#中的关键字),因为我在编译时不知道属性名称;
  • 我不能使用反射,因为它只检索静态类型信息;
  • IDictionary<string, object>我所知,转换为只解决了选择实现该接口的动态类的情况(例如ExpandoObject).

这是演示代码:

    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();
    }
Run Code Online (Sandbox Code Playgroud)

Jea*_*nal 6

我终于可以通过使用C#运行时绑定器来完成它.(我相信应该可以通过更简单的绑定器实现来实现这一点,但我无法编写一个工作的 - 可能编写一个"简单"的实现已经非常困难了).

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();
    }
Run Code Online (Sandbox Code Playgroud)

输出:

StatValue
StatValue
ExpandoValue
ExpandoValue
Run Code Online (Sandbox Code Playgroud)