我正在编写代码以将我的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作为对象返回...
答案 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
这样的值类型不会被装箱,并且保留了类型安全性)