我有一些非常动态的代码,最初使用Type.GetProperty
和PropertyInfo.GetValue
的反射来获取对象的值。然后我读到了GetValue
:
https://lotsacode.wordpress.com/2010/04/12/getting-data-through-reflection-getvalue/
并决定尝试通过创建和缓存代表来改进事物,就像他们在帖子中所做的那样。所以我创建了这样的东西:
private Delegate MakeAccessDelegate(PropertyInfo p)
{
var delType = typeof(Func<,>);
var genType = delType.MakeGenericType(p.DeclaringType, p.PropertyType);
var mi = p.GetAccessors().First();
return Delegate.CreateDelegate(genType, mi);
}
但是,因为我不知道委托的类型,所以我被迫使用DynamicInvoke
,这是好的一面,没有GetValue
更糟糕,但是没有似乎也更好。
所以我搜索了一下,发现了这个问题并回答:
alternative for using slow DynamicInvoke on muticast delegate
接受的答案建议使用已编译的委托,这听起来像是可以帮助很多的东西。由于我的方法只是属性获取者,我需要稍微更改它并提出这个(我对表达树没有任何了解,所以我在这里飞得有点盲目):
delegate object CachedMethodDelegate(object instance);
private CachedMethodDelegate MakeAccessDelegate(PropertyInfo p)
{
var methodInfo = p.GetAccessors().First();
var instance = Expression.Parameter(typeof(object), "instance");
var lambda = Expression.Lambda<CachedMethodDelegate>(
Expression.Call(
Expression.Convert(instance, methodInfo.DeclaringType),
methodInfo
),
instance
);
return lambda.Compile();
}
这似乎有效。除了一个小皱纹。如果属性是值类型(例如double
或datetime
),则它无法创建lambda。它会在行ArgumentException
上抛出var lambda = ...
并出现错误:
Expression of type 'System.Nullable`1[System.Double]' cannot be used
for return type 'System.Object'
显然,它无法处理值类型的自动装箱和拆箱。有没有办法使这项工作?
答案 0 :(得分:2)
在Expression.Convert
的结果上致电Expression.Call
并将其转换为object
。如果需要将类型装箱,这将导致装箱操作。