这个灵感来自我的语言大师同事,他似乎无法为它们找到一个好的用途,在我自己的几次蹩脚尝试之后,我不得不同意。
现在我知道,一旦你掌握了一些好的实际理由,这些概念往往会更容易流动。
目前,它的唯一目的似乎是让您编写一个 Linq 提供程序?
是这样吗??这还有其他好处吗?
这个灵感来自我的语言大师同事,他似乎无法为它们找到一个好的用途,在我自己的几次蹩脚尝试之后,我不得不同意。
现在我知道,一旦你掌握了一些好的实际理由,这些概念往往会更容易流动。
目前,它的唯一目的似乎是让您编写一个 Linq 提供程序?
是这样吗??这还有其他好处吗?
表达式树之所以如此强大,是因为它们让您可以将代码视为数据。用户习惯于构建数据、保存数据并稍后返回。
表达式树可以让你用代码做同样的事情。例如,您可以获取用户的输入(复选框、数字范围等)并将其转换为表达式树。然后可以执行该表达式树,或将其存储起来供以后使用。很酷。
想想围绕报告的实际用途,例如建立和保存数据过滤器和数据映射。另一个实际用途是根据用户定义的规则在应用程序中支持自定义工作流。
这里有一些关于序列化表达式树 ( http://code.msdn.microsoft.com/exprserialization ) 的 MSDN 代码,应该可以让想法流动起来。
您可以使用表达式树将域语言转换为可执行代码。
寻找问题的解决方案是吗?
表达式树允许您将代码呈现为可转换的数据结构,因此它们非常适合在语言之间转换 Linq To SQL 是目前最强大的。
除了 DSL(即转换)之外的另一个用途是并行化(即拆分),该领域的示例是 PLINQ。
.NET 4.0 表达式树也是 DLR AST 的基础
快速回答是“不,它现在不仅适用于 LINQ 提供程序”。首先,动态语言运行时扩展了表达式树以支持动态语言。基本上,如果您想将自己的动态语言移植到 .NET(就像 IronPython 和 IronRuby 一样),您将不得不使用表达式树。好吧,没有多少人有自己的语言。其他用例是什么?其中之一是在运行时生成动态代码。我在这里有一个例子:Generating Dynamic Methods with Expression Trees in Visual Studio 2010。它解释了如何使用 ET 而不是生成 MSIL 来创建动态方法。事实上,即使在 .NET 3.5 中,也有一些在 LINQ 之外的表达式树用例,但这些帖子还没有写完。
我在他们将我的领域特定语言 AST 转换为表达式树方面有很好的经验。使用ANTLR树适配器直接从语法创建表达式树也相当容易。
看到这篇文章:http ://codebetter.com/blogs/gregyoung/archive/2009/10/03/delegate-mapper.aspx 这是一个很好的用例。
您可以将表达式树用作具有更高抽象级别的代码构建器,然后程序集发出并且比 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();
}
}
(对损坏的代码格式感到抱歉)