【问题标题】:Property get/set Delegates for runtime reflected class运行时反射类的属性获取/设置委托
【发布时间】:2011-04-09 23:58:51
【问题描述】:

我了解 Delegates 提供的高性能反射可能仅比常规显式 c# 代码慢 15%。但是,我可以在 stackoverflow 上找到的所有示例都是基于对通过委托访问的方法/属性类型的先验知识。

考虑到此类的先验知识,为什么首先要使用反射代理访问?

无论如何,我面临的反射编码任务是如何为在运行时仅提供类类型名称的未知类属性列表实现高性能属性获取/设置访问?我可以编写反射检查的基础知识以生成属性列表,但是如何为一组可能随机的属性类型连接一组基于 Delegate 的访问器?

假设属性类型仅限于一系列基本 DB 列类型,答案是 case 语句返回:

Func<int> or Func<string> etc? 

Edit-1:我仅限于 .Net 3.5

【问题讨论】:

  • 您在寻找 typeof(Func).MakeGenericType(myDbType); 吗?还是您也需要委托的实现?此外,events 的概念是代表的一种常见的基于非反射的使用场景。 Enumerable 的扩展方法也为委托/lambda 的实用性提供了丰富的示例。
  • @Kirk。对于我需要通过委托设置器填充的每个类,我需要保存这些设置器的数组。在填充 Delegate setter 数组时,我需要根据我刚刚通过反射发现的 Property 类型来制造一个 Delegate。 MakeGenericType() 对我来说似乎是缺少的链接。

标签: c# delegates properties


【解决方案1】:

此解决方案使用表达式树,因为它们相当容易组合,并且它们提供了方便的 Compile() 方法来获取您可以调用的实际委托。我让 Func 实际上接受了对象(所以 Func 而不仅仅是 Func),因此您可以从任何实例中获取属性值。

编辑:也添加了 setter 实现。

public class MyClass
{
    public string MyStringProperty { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        PropertyInfo propertyInfo = typeof(MyClass).GetProperty("MyStringProperty");
        Delegate getter = CreateGetter(propertyInfo);
        Delegate setter = CreateSetter(propertyInfo);
        object myClass = new MyClass();
        setter.DynamicInvoke(myClass, "Hello");
        Console.WriteLine(getter.DynamicInvoke(myClass));
    }

    public static Delegate CreateGetter(PropertyInfo property)
    {
        var objParm = Expression.Parameter(property.DeclaringType, "o");
        Type delegateType = typeof(Func<,>).MakeGenericType(property.DeclaringType, property.PropertyType);
        var lambda = Expression.Lambda(delegateType, Expression.Property(objParm, property.Name), objParm);
        return lambda.Compile();
    }

    public static Delegate CreateSetter(PropertyInfo property)
    {
        var objParm = Expression.Parameter(property.DeclaringType, "o");
        var valueParm = Expression.Parameter(property.PropertyType, "value");
        Type delegateType = typeof(Action<,>).MakeGenericType(property.DeclaringType, property.PropertyType);
        var lambda = Expression.Lambda(delegateType, Expression.Assign(Expression.Property(objParm, property.Name), valueParm), objParm, valueParm);
        return lambda.Compile();
    }
}

首先使用动态setter将其设置为“Hello”,然后使用动态getter从对象中获取属性,从而打印出“Hello”。

【讨论】:

  • @Kirk。谢谢,这似乎接近我所需要的。我在原始问题中应该更清楚,属性设置是我的主要编码任务。我可能可以从 TypedelegateType = .. MakeGenericType() 中获取它,然后使用标准的 Jon Skeet 和 Marc Gavell 关于这个主题的帖子缝合你的代码。我假设 Lambda 不会在 Delegate 属性设置场景中发挥作用?
  • @camelCase,setter 也使用表达式树/lambdas。请参阅我的更新答案。
  • @柯克。感谢您的设置器代码示例。根据文档,一个问题 Expression.Assign() 是 .Net 4.0,找到 .Net3.5 替代方案是我需要调查的。
  • Expression.Assign 只是一种方便的方法,用于“NodeType 属性等于 Assign 且 Left 和 Right 属性设置为指定值的 BinaryExpression”。我想您应该能够以这种方式自己创建 BinaryExpression。
  • @James,表达式树的好处在于您只是在尝试重新创建您已经知道如何在 C# 中本地执行的表达式。我建议只浏览Expression 类并简单地尝试其中的每个函数。一旦您对 API 有了一定的实践经验,您就会真的觉得自己可以编写任何类型的表达式。
猜你喜欢
  • 1970-01-01
  • 2018-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-04
  • 2017-11-08
  • 2012-03-25
  • 1970-01-01
相关资源
最近更新 更多