从编译表达式返回值类型

时间:2015-01-19 16:47:52

标签: c# lambda boxing

我有一些非常动态的代码,最初使用Type.GetPropertyPropertyInfo.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();
}

这似乎有效。除了一个小皱纹。如果属性是值类型(例如doubledatetime),则它无法创建lambda。它会在行ArgumentException上抛出var lambda = ...并出现错误:

Expression of type 'System.Nullable`1[System.Double]' cannot be used 
for return type 'System.Object'

显然,它无法处理值类型的自动装箱和拆箱。有没有办法使这项工作?

1 个答案:

答案 0 :(得分:2)

Expression.Convert的结果上致电Expression.Call并将其转换为object。如果需要将类型装箱,这将导致装箱操作。

相关问题