c# - 在编译器生成的表达式树中使用表达式

标签 c# linq

我知道我可以使用以下方法创建表达式树:

  1. 工厂方法。

  2. 将 lambda 表达式编译器转换为 Expression

对于复杂的表达式树,我更喜欢 2,因为它更简洁。

是否可以使用这种方式引用已经构建的表达式

using System;
using System.Linq.Expressions;

public class Test
{
    public static Expression<Func<int, int>> Add(Expression expr)
    {
#if false
        // works
        ParameterExpression i = Expression.Parameter(typeof(int));
        return Expression.Lambda<Func<int, int>>(Expression.Add(i, expr), i);
#else
        // compiler error, can I pass expr here somehow?
        return i => i + expr;
#endif
    }

    public static void Main()
    {
        Func<int, int> f = Add(Expression.Constant(42)).Compile();
        Console.WriteLine(f(1));
    }
}

最佳答案

没有任何现成的东西,但您可以自己构建一个工具来提供此功能。

您可以编写一个接受具有两个参数的表达式的方法,一个是“真实”参数,另一个是您要用另一个表达式的值替换的某个值的参数。然后,您可以使用一个解析为该值的表达式,并将该参数的所有实例替换为第二个表达式:

public static Expression<Func<TSource, TResult>> BuildExpression
    <TSource, TOther, TResult>(
    Expression<Func<TSource, TOther, TResult>> function,
    Expression<Func<TOther>> innerExpression)
{
    var body = function.Body.Replace(function.Parameters[1], innerExpression.Body);
    return Expression.Lambda<Func<TSource, TResult>>(body, function.Parameters[0]);
}

您可以使用以下方法将一个表达式的所有实例替换为另一个表达式:

public static Expression Replace(this Expression expression,
    Expression searchEx, Expression replaceEx)
{
    return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
internal class ReplaceVisitor : ExpressionVisitor
{
    private readonly Expression from, to;
    public ReplaceVisitor(Expression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    public override Expression Visit(Expression node)
    {
        return node == from ? to : base.Visit(node);
    }
}

然后您可以按如下方式将其应用到您的案例中:

public static Expression<Func<int, int>> Add(Expression<Func<int>> expr)
{
    return BuildExpression((int i, int n) => i + n, expr);
}

关于c# - 在编译器生成的表达式树中使用表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26999406/

相关文章:

c# - 如何使用 Linq 确定 List<T> 中的所有对象是否具有相同的属性值

c# - LINQ SelectMany 和 Where 扩展方法忽略空值

c# - MemoryFailPoint 在 WinXP 64 早期触发

c# - XNA 中的 Unicode 字符串显示

c# - 序列在 Entity Framework 代码优先迁移中包含多个元素错误

c# - 使用 `new PrincipalContext(ContextType.Domain, "domain.name.com")` 而无需提供用户名和密码

Linq GroupInto 选择器

c# - 超时已过。在操作完成之前超时期限已过,或者服务器没有响应。该语句已终止

c# - LINQ to Entities 查询错误

.net - 如何使不需要的命名空间默认不出现在新类之上