什么是.net 4.0 Expression Trees的一个很好的用例?

时间:2009-10-07 16:07:54

标签: .net linq expression-trees

这个灵感来自我的语言大师同事,他似乎无法为他们找到一个好用的东西,经过我自己的几次蹩脚尝试后,我不得不同意。

现在我知道,一旦你有一些很好的实际原因,这些概念往往会更容易流动。

目前似乎唯一的目的是让你写一个Linq提供者?

是吗?这还有其他好处吗?

9 个答案:

答案 0 :(得分:16)

表达式树非常强大,因为它们可以让您像数据一样处理代码。用户习惯于构建数据,保存数据并稍后再返回。

表达式树可以让你用代码做同样的事情。例如,您可以获取用户的输入(复选框,数字范围等)并将其转换为表达式树。然后可以执行该表达式树,或将其存储以供以后使用。很酷。

考虑报告的实际用途,例如构建和保存数据过滤器和数据映射。另一个实际用途是根据用户定义的规则支持应用程序中的自定义工作流程。

这里有一些关于序列化表达式树(http://code.msdn.microsoft.com/exprserialization)的MSDN代码,它们可以让想法流动起来。

答案 1 :(得分:8)

您可以使用表达式树将域语言转换为可执行代码。

答案 2 :(得分:4)

寻找问题的解决方案呃?

表达式树允许您将代码呈现为可转换的数据结构,因此它们非常适合在当前最强大的Linq To SQL语言之间进行转换。

除DSL之外的其他用途(即转换)是并行化(即拆分),并且该空间中的示例是PLINQ。

答案 3 :(得分:3)

.NET 4.0表达式树也是DLR AST的基础

答案 4 :(得分:2)

快速回答是“不,现在不仅仅是针对LINQ提供商”。首先,动态语言运行库扩展了表达式树以支持动态语言。基本上,如果你想将自己的动态语言移植到.NET(就像IronPython和IronRuby那样),你将不得不使用表达式树。 好的,没有那么多人拥有自己的语言。还有什么其他用例?其中之一是在运行时生成动态代码。我在这里有一个例子:Generating Dynamic Methods with Expression Trees in Visual Studio 2010。它解释了如何使用ET而不是生成MSIL来创建动态方法。 实际上,即使在.NET 3.5中,LINQ之外的表达式树也有一些用例,但这些帖子还没有写出来。

答案 5 :(得分:1)

我有很好的经验,他们将我的域特定语言AST转换为表达式树。使用ANTLR树适配器直接从语法创建表达式树也很容易。

答案 6 :(得分:1)

看到这篇文章:http://codebetter.com/blogs/gregyoung/archive/2009/10/03/delegate-mapper.aspx 这是一个很好的用例。

答案 7 :(得分:1)

您可以将表达式树用作具有更高抽象级别的代码构建器,然后组件发出并比CodeCompiler更快。以下是我用来说服我们团队将其用作CodeCompiler的替代品的概念的一些证明。

[TestClass]
public class WhenINeedToAccessPropertiesByNameHavingATypeReference
{
    public class SomeCategoryData
    {
        public DateTime CreatedDate { get; set; }
    }

    [TestMethod]
    public void ICanDoThatWithAnExpressionAndItPerformsWell()
    {
        // INIT

        var someCategoryData =
            Enumerable.Range(1970, 100).Select(year =>
                new SomeCategoryData { CreatedDate = new DateTime(year, 1, 1) }).Cast<object>();
        var t = typeof(SomeCategoryData); // or it can be: t = someCategoryData.First().GetType();
        var compiled = Stopwatch.StartNew();

        // ACT

        var filter = AccessPropertyByNameInCompiledMannerSomehow(t, "CreatedDate");

        // ASSERT

        Trace.WriteLine(string.Format("compiled in: {0}", compiled.Elapsed));
        Assert.IsTrue(compiled.ElapsedMilliseconds < 3, "compiles fast enough");

        var executed = Stopwatch.StartNew();

        // ACT
        List<object> result = null;
        for (var i = 0; i < 10000; i++)
        {
            result = someCategoryData.Where(d => filter(d, new DateTime(2000, 1, 1), new DateTime(2009, 1, 1)))
                .ToList();
        }
        executed.Stop();
        Trace.WriteLine(string.Format("executed in: {0}", executed.Elapsed));

        // ASSERT
        Assert.AreEqual(10, result.Count, "insure compiled code actually works");
        Assert.IsTrue(executed.ElapsedMilliseconds < 300, "runs fast enough");
    }

    private static Func<object, DateTime, DateTime, bool>
        AccessPropertyByNameInCompiledMannerSomehow(Type t, string fieldToFilterBy)
    {
        var objectParameter = Expression.Parameter(typeof(object), "p");
        var instance = Expression.Convert(objectParameter, t);
        var lower = Expression.Parameter(typeof(DateTime), "l");
        var upper = Expression.Parameter(typeof(DateTime), "u");

        var composite = Expression.Lambda<Func<object, DateTime, DateTime, bool>>(
            Expression.And(
                Expression.LessThanOrEqual(
                    lower,
                    Expression.PropertyOrField(instance, fieldToFilterBy)
                    ),
                Expression.GreaterThanOrEqual(
                    upper,
                    Expression.PropertyOrField(instance, fieldToFilterBy)
                    )
                ), objectParameter, lower, upper
            );

        return composite.Compile();
    }
}

答案 8 :(得分:1)

我有几个例子here

(对于破解的代码格式化感到抱歉)