创建函数以检索通过反射检索的属性的值

时间:2016-09-20 16:53:29

标签: c# reflection

我正在编写代码以将我的ORM实体的数据传输到数据集中。因为我不想为定义需要写下哪些属性的每种类型编写特殊代码,所以我当前正在使用反射(在实体类型上调用GetProperties,为此类型构建DataTable,然后在每个Propertyinfo上调用GetValue每个实体)。现状:它有效,但速度很慢。

现在我正在尝试构建一个返回函数的方法来快速检索某些属性的值,但我在这里遇到了困难。这是我到目前为止所得到的:

  /// <summary>
  /// creates a func that will return the value of the given property 
  /// </summary>
  /// <typeparam name="T">type of the entity</typeparam>
  /// <param name="propertyInfo">the property to get the value from</param>
  /// <returns>a function accepting an instance of T and returning the value of the property</returns>
  private Func<T, object> CreateGetPropertyFunc<T>(PropertyInfo propertyInfo)
   {         
     MethodInfo getMethod = propertyInfo.GetGetMethod();
     return (Func<T, object>)Delegate.CreateDelegate(typeof(Func<T, object>), getMethod);          
  }

这些是我的单元测试:

  [TestMethod]
  public void TestGenerateDelegate()
  {
     var employee = new Employee
     {            
        Id = 1,
        Name = "TestEmployee",            
     };

     Func<Employee, object> getIdValueFunc = CreateGetPropertyFunc<Employee>(typeof(Employee).GetProperty("Id"));
     Assert.AreEqual(1, getIdValueFunc(employee));
  }

    [TestMethod]
    public void TestGenerateDelegateName()
    {
        var employee = new Employee
        {
            Name = "Test"
        };

        Func<Employee, object> getNameValueFunc = CreateGetPropertyFunc<Employee>(typeof(Employee).GetProperty("Name"));
        Assert.AreEqual("Test", getNameValueFunc(employee));
    }

当我调用第一个时,抛出一个带有消息“绑定到目标方法时异常”(已翻译,可能是不同的文本)的ArgumentException。第二次测试通过了。

我很确定我没有正确处理CreateDelegate方法。有人能指出我正确的方向吗?

更新:

作为PetSerAI状态,它似乎是方差的问题,值原始类型不能通过CreateDelegate作为对象返回...

4 个答案:

答案 0 :(得分:2)

您只需调用getMethod

即可
private Func<T, object> CreateGetPropertyFunc<T>(PropertyInfo propertyInfo)
{
    MethodInfo getMethod = propertyInfo.GetGetMethod();
    return o => getMethod.Invoke(o, BindingFlags.Default, null, null, CultureInfo.CurrentCulture);
}

答案 1 :(得分:1)

CreateDelegate(Type, MethodInfo)绑定到静态方法(你没有静态方法,这就是你得到错误的原因)

对于此版本,您只能使用Delegate.CreateDelegate实例方法:CreateDelegate(Type, Object, MethodInfo)

  

创建表示指定类型的指定类型的委托   static或instance方法,带有指定的第一个参数。

https://msdn.microsoft.com/en-us/library/system.delegate.createdelegate(v=vs.110).aspx

根据PetSerAl的评论,你应该通过&#39; null&#39;作为第一个论点&#39;创建一个&#34;开放代表&#34;你将传递实例。

    // In this case, the delegate has one more 
    // argument than the instance method; this argument comes
    // at the beginning, and represents the hidden instance
    // argument of the instance method. Use delegate type D1
    // with instance method M1.
    //
    d1 = (D1) Delegate.CreateDelegate(typeof(D1), null, mi1);

    // An instance of C must be passed in each time the 
    // delegate is invoked.
    //
    d1(c1, "Hello, World!");

答案 2 :(得分:1)

您可以使用表达式树动态创建委托,该委托引用指定的属性:

private Func<T, object> CreateGetPropertyFunc<T>(PropertyInfo propertyInfo) {
    ParameterExpression p = Expression.Parameter(typeof(T));
    return Expression.Lambda<Func<T, object>>(
        Expression.Convert(Expression.Property(p, propertyInfo), typeof(object)),
        p
    ).Compile();
}

答案 3 :(得分:0)

为什么不一直使用泛型并让编译器为你创建委托?

public static class Ext
{
    public static Func<T, TProp> CreateGetPropertyFunc<T, TProp>(this T obj, Func<T, TProp> func)
    {
        return func;
    }
}

然后:

var getterForId = employee.CreateGetPropertyFunc(x => x.Id);
int result = getterForId(employee);
// result can now be 'int' and doesn't have to be 'object'

如果您没有预先设置T的实际实例,或者只是不想使用扩展方法方法:

public Func<T, object> CreateGetPropertyFunc<T>(Func<T, object> func)
{
    return func;
}

然后:

var getterForId = CreateGetPropertyFunc<Employee>(x => x.Id);
object result = getterForId(employee);
// result must be 'object' (unless explicitly casted)

(前者在性能方面更好,因为像int这样的值类型不会被装箱,并且保留了类型安全性)