Expression.Reduce()有什么作用?

d..*_*d.. 35 .net c# lambda expression-trees

我已经使用表达式树几天了,我很想知道Expression.Reduce()的作用.在MSDN文档是不是非常有帮助,因为它只是说,它"减少"的表述.为了以防万一,我尝试了一个例子(见下文)来检查这种方法是否包括数学减少,但似乎并非如此.

有谁知道这种方法的作用,是否有可能提供一个快速示例显示它的实际效果?有什么好资源吗?

static void Main(string[] args)
{
    Expression<Func<double, double>> func = x => (x + x + x) + Math.Exp(x + x + x);
    Console.WriteLine(func);
    Expression r_func = func.Reduce();
    Console.WriteLine(r_func); // This prints out the same as Console.WriteLine(func)
}
Run Code Online (Sandbox Code Playgroud)

Ale*_*ina 29

您需要查看的文档是"expr-tree-spec.doc":http://dlr.codeplex.com/wikipage?title = Docs%20and%20specs&referringTitle = Document

这是表达式树的规范.阅读"2.2 Redusible Nodes"和"4.3.5 Reduce Method"部分.

基本上,此方法适用于将其动态语言实现或移植到.NET的人员.这样他们就可以创建自己的节点,可以"减少"到标准表达式树节点并可以编译.表达式树API中有一些"可简化"节点,但我不知道你是否可以得到任何实际的例子(因为所有标准表达式节点无论如何编译,因为最终用户你可能不关心它们是否"减少" "幕后与否".

是的,MSDN文档在这方面非常基础,因为语言实现者的信息和文档的主要来源是http://dlr.codeplex.com/

  • 在这种特殊情况下,这是我的错.我忘了将codeplex的链接添加到System.LINQ.Expressions并且只将它添加到System.Dynamic.考虑它"文档错误".我将尝试修复它以进行下一次文档更新,通常每月发生一次. (2认同)

Nic*_*era 23

通过稍微拆解,我发现Expression.CanReduce总是重新出现,false而Expression.Reduce()总是返回this.但是,有一些类型可以覆盖它们.LambdaExpression继承了默认实现,这解释了为什么到目前为止已经尝试过的表达式不起作用.

覆盖Reduce()的其中一种类型是MemberInitExpression,这使我进行了以下成功的实验:

class ReduceFinder : ExpressionVisitor {
    public override Expression Visit(Expression node) {
        if (node != null && node.CanReduce) {
            var reduced = node.Reduce();
            Console.WriteLine("Found expression to reduce!");
            Console.WriteLine("Before: {0}: {1}", node.GetType().Name, node);
            Console.WriteLine("After: {0}: {1}", reduced.GetType().Name, reduced);
        }
        return base.Visit(node);
    }
}

class Foo {
    public int x;
    public int y;
}

static class Program {
    static void Main() {
        Expression<Func<int, Foo>> expr = z => new Foo { x = (z + 1), y = (z + 1) };
        new ReduceFinder().Visit(expr);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Found expression to reduce!  
Before: MemberInitExpression: new Foo() {x = (z + 1), y = (z + 1)}  
After: ScopeN: { ... }  
Run Code Online (Sandbox Code Playgroud)


Joe*_*han 6

这是一个相当古老的问题,但它似乎有点兴趣,所以我在这个额外的响应中添加了关于现在开箱即用的.NET内容的信息.

据我所知,Reduce()仅在复杂的操作中被覆盖,这些操作将作为其工作的一部分实现.似乎有三个关键方案.

  1. 复合赋值扩展为离散二进制算术和赋值操作; 换一种说法,

    x += y

    x = x + y.

  2. 预增量和后增量运算符扩展到其离散运算.对于预增/减,

    ++x

    变得大约:

    x = x + 1

    x++

    变得大约:

    temp = x;
    x = x + 1;
    temp;
    
    Run Code Online (Sandbox Code Playgroud)

    我说大概是因为操作没有实现为x + 1左操作数的二进制操作,x右操作数是常量1但是作为一元递增/递减操作.净效果是一样的.

  3. 成员和列表初始化程序从简短形式扩展为长形式.所以:

    new Thing() { Param1 = 4, Param2 = 5 }

    变为:

    temp = new Thing();
    temp.Param1 = 4;
    temp.Param2 = 5;
    temp;
    
    Run Code Online (Sandbox Code Playgroud)

    和:

    new List<int>() { 4, 5 }

    变为:

    temp = new List<int>();
    temp.Add(4);
    temp.Add(5);
    temp;
    
    Run Code Online (Sandbox Code Playgroud)

这些更改是否使一个人更容易或更难实现解析表达式树的内容是一个观点问题,但最重要的是,这似乎是.NET框架中开箱即用的减少级别.