从编译表达式返回值类型

Returning value type from compiled expression

我有一些非常动态的代码,这些代码最初使用 Type.GetPropertyPropertyInfo.GetValue 的反射来从对象中获取值。然后我读了这篇关于 GetValue:

的表现

https://lotsacode.wordpress.com/2010/04/12/getting-data-through-reflection-getvalue/

并决定像在 post 中那样通过创建和缓存委托来尝试改进。所以我创建了这样的东西:

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

接受的答案建议使用编译委托,这听起来很有帮助。由于我的方法只是属性 getters,我需要稍微改变一下并想出这个(我对表达式树一无所知,所以我在这里有点盲目):

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。它在行 var lambda = ... 上抛出一个 ArgumentException 错误:

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

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

Expression.Call 的结果调用 Expression.Convert 并将其转换为 object。这样就会在需要对类型进行装箱的情况下进行装箱操作。