繁体   English   中英

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

[英]Creating functions to retrieve values of properties retrieved via 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将值原始类型作为对象返回...

您可以只调用getMethod

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

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

您只能将此实例的实例方法使用Delegate.CreateDelegateCreateDelegate(Type, Object, MethodInfo)

使用指定的第一个参数创建表示指定的静态方法或实例方法的指定类型的委托。

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

根据PetSerAl的评论,您应将“ null”作为“第一个参数”传递,以创建一个“开放委托”,您将实例传递到其中。

    // 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!");

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

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();
}

为什么不完全采用通用方法,让编译器为您创建委托?

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类的值类型装箱,并且保留类型安全性)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM