【问题标题】:How can I, using the C# lambda expression syntax, invoke another expression?如何使用 C# lambda 表达式语法调用另一个表达式?
【发布时间】:2011-09-04 10:09:52
【问题描述】:

.NET 表达式类型支持表示调用由另一个表达式定义的函数,但是有没有一种方法可以使用 C# lambda 表达式语法来表达这一点?我可以生成一个表达式,编译它并在另一个表达式中调用它,但这会失去被调用的 lambda 的“表达式”,并且调用表达式将只包含对匿名编译函数的引用。

也就是说,我想做的是:

Expression<Func<int, int>> f = x => x + x;
Expression<Func<int, int>> g = x => 2 + f(x);

但由于直接调用表达式是无效的,我最接近的是:

Expression<Func<int, int>> f = x => x + x;
var f_ = f.Compile();
Expression<Func<int, int>> g = x => 2 + f_(x);

...它失去了被调用的函数 f 是一个表达式这一事实。

【问题讨论】:

    标签: .net linq expression-trees


    【解决方案1】:

    我不相信这在编译器的帮助下目前是可能的(从 C# 4.0 开始),但您当然可以使用 Expression.Invoke“手动”完成。

    创建一个应用委托或 lambda 的 InvocationExpression 表达式到参数表达式列表。

    在你的情况下,这看起来像:

    Expression<Func<int, int>> f = x => x + x;
    
    var parameter = Expression.Parameter(typeof(int),"y");
    var body = Expression.Add(Expression.Constant(2), Expression.Invoke(f, parameter));
    
    // Loosely speaking: y => 2 + f(y)
    var g = Expression.Lambda<Func<int, int>>(body, parameter);
    

    LINQKit 提供了 Invoke /Expand 扩展方法来为您完成工作,让您能够使用 lambdas 来实现这一点。这会让你做:

    Expression<Func<int, int>> f = x => x + x;
    Expression<Func<int, int>> g = x => 2 + f.Invoke(x);
    
    // Note: 'Inlines' the invocation into the target expression.
    var finalExpression = g.Expand();
    

    ..这非常接近你最初想要的语法。

    关于InvocationExpressions 需要注意的一点是,一些 LINQ 提供程序(例如 LINQ to Entities)根本不喜欢它们;因此,您经常不得不“扩展”调用的表达式,使其看起来像提供者的一个表达式。您当然可以手动执行此操作,但 LINQKit 再次通过 AsExpandable 扩展名派上用场。

    【讨论】:

    • 是的,我找到了 Expression.Invoke 和 InvocationExpression,这就是我知道可以表示的方式。我很惊讶没有办法使用 lambda 表达式语法来表达这一点。事实上,使用 lambda 语法无法创建的所有表达式类型到底是什么,大多数 LINQ 提供程序是否支持它们?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多