将 Expression<Func<T, U>> 转换为 Expression<Func<object, object>>

l33*_*33t 3 c# lambda expression-trees

我有一个LambdaExpression类型为Expression<Func<T, string>>. 代码的设计目前不允许我保留T,这意味着我被迫使用较慢的DynamicInvoke而不是Invoke.

因为我知道T我想要转换表达式的类型,以便它接受一个T对象,允许我使用Invoke. 如何?

这是一个好的开始

class Program
{
    class MyClass
    {
        public string MyProperty => "Foo";
    }

    static LambdaExpression GetExpression(Expression<Func<MyClass, object>> expr)
    {
        return expr;
    }

    static void Main(string[] args)
    {
        var e1 = GetExpression(t => t.MyProperty);
        var e2 = Expression.Lambda<Func<object, object>>(e1, e1.Parameters);

        object myClass = new MyClass();
        string s1 = (string)e1.Compile().DynamicInvoke(myClass);
        object s2 = e2.Compile().Invoke(myClass);
    }
}
Run Code Online (Sandbox Code Playgroud)

小智 5

非表达式版本看起来像

Func<object, object> Convert<T>(Func<T, object> f) {
  return o => f((T)o);
}
Run Code Online (Sandbox Code Playgroud)

这也是您在表达式版本中需要执行的操作。你说得对,Expression.Convert可以做到。

Expression<Func<MyClass, object>> e1 = t => t.MyProperty;
var p = Expression.Parameter(typeof(object));
var e2 = Expression.Lambda<Func<object, object>>(
    Expression.Invoke(e1, Expression.Convert(p, typeof(MyClass))), p);
Run Code Online (Sandbox Code Playgroud)

注意:正如@xanatos 正确指出的那样,对于转换 egExpression<Func<T, int>>Expression<Func<object, object>>,尽管 C# 支持从intto的隐式装箱转换object,但表达式树不支持。如果这与问题有关,Expression.Convert则需要另一个。