【问题标题】:Whats a good use case for .net 4.0 Expression Trees?.net 4.0 表达式树有什么好的用例?
【发布时间】:2009-10-07 16:07:54
【问题描述】:

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

现在我知道,一旦您掌握了一些好的实际理由,这些概念往往会更容易流动。

目前看来,它的唯一目的是让您编写一个 Linq 提供程序?

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

【问题讨论】:

标签: .net linq expression-trees


【解决方案1】:

表达式树之所以如此强大,是因为它们可以让您将代码视为数据。用户习惯于构建数据、保存数据并稍后返回。

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

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

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

【讨论】:

  • 酷!这是一个符合我特定心态的答案。很好的例子!我现在看到了它是如何在框架的其他部分中使用的。那么这在 WPF 中是否被大量使用?
  • 谢谢。很高兴这有帮助。我对 WPF 的思考(可能太多了)以及像 lambda 和表达式树这样的疯狂有用的函数式编程概念将成为核心。问题是 WPF 是在 .NET 3.0 中发布的,而 LINQ 是在 .NET 3.5 中发布的。展望未来,我希望 WPF/Silverlight 团队能够重组。除了所有该死的字符串外,XAML 都可以:)。启动 Relector,看看他们必须为 System.Windows.DataTrigger 之类的东西做些什么。他们的悲叹可能是 LINQ 的催化剂。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    寻找问题的解决方案是吗?

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

    除了 DSL(即转换)之外的另一个用途是并行化(即拆分),该领域的示例是 PLINQ。

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              【解决方案8】:

              我有几个例子here

              (抱歉,代码格式损坏)

              【讨论】:

                【解决方案9】:

                您可以将表达式树用作具有更高抽象级别的代码构建器,然后程序集发出并且比 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();
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 2021-12-19
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-05-08
                  • 2014-01-13
                  相关资源
                  最近更新 更多