表达树目的:
表达式树必须是 在可以使用之前编译。这是因为表达式树是 实际上是一个数据结构,而不是编译代码。为什么?因为这段代码 预计将用于电线,或者 - 换句话说 - 用于其他 进程(可能在其他计算机上运行)。
来自: http://geekswithblogs.net/Martinez/archive/2009/06/29/understanding-expression-trees.aspx
'数据结构'和'编译代码'之间有什么区别;如何在C#中使用comipled代码?通过本文,我了解到每个不包含Array或List的行都是编译代码(例如:“Human H1 = new Human(18);”)。
请不要告诉我什么是表达式树的例子,我想要一个关于这个问题的明确答案。
感谢您的时间
答案 0 :(得分:3)
你不能先编译表达式树而不先编译它,因为表达式树有不同的用途:它们可以作为可执行代码的灵活蓝图,而不是可执行代码本身(相当不灵活)。
表达式树是描述代码(已编译或未编译)的数据结构,其抽象级别高于代码本身。与代码不同,可以操纵数据结构以形成描述其他代码段的不同结构。与数据结构不同,可以评估代码以产生结果。
考虑这个例子:
Expression p1 = Expression.Parameter(typeof(int), "a");
Expression p2 = Expression.Parameter(typeof(int), "b");
Expression expr = Expression.Add(p1, p2);
它显示正在创建的表达式expr
,描述了一个简单的表达式树a+b
。此时,我们有一个树状数据结构,有三个节点 - 两个节点代表参数,一个节点代表加法。我们可以使用表达式树做很多事情,例如检查其内容,查找其返回类型等等。我们甚至可以操纵它的结构来基于它构建其他表达式:例如,我们可以添加第三个参数,然后生成a+b+c
,如下所示:
Expression p3 = Expression.Parameter(typeof(int), "c");
expr = Expression.Add(expr, p3);
然而,我们做不到的一件事是传递两个整数值并获得它们的总和:表达式树不提供评估它们的方法。为此,您需要真实的代码,而不是代码的描述。
表达式树提供了一种通过编译将代码描述转换为代码的方法。将表达式树创建为lambda并在其上调用Compile()
方法后,您将获得一个如下所示的已编译CIL代码:
ldarg.0
ldarg.1
add
ret
此代码可以传递两个值进行评估,它会将总和返回给您。但是,某些信息在翻译中会丢失:具体而言,参数a
和b
的名称在编译代码中不再存在:它们不是执行计算所必需的,因此它们已被删除。 / p>
答案 1 :(得分:2)
您必须在编写的上下文中读取该语句:表达式树是一种数据结构,因此在编译表达式树之前,无法计算它表示的表达式。
让我们这样说:在构建项目时,下面的表达式将被编译。但是,运行应用程序时所发生的一切就是它将构建一个表达式树(即数据结构)。
Expression<Func<int, int, bool>> f = (a, b) => a < b;
为了实际执行表达式f
,您必须编译它f.Compile()
。请注意,有两个编译发生:
为什么我不能在没有f.Compile()的情况下执行它?这就是我真正想问的问题
Expression.Compile
方法“将表达式树描述的lambda表达式编译成可执行代码......”如果您没有可执行代码,则无法执行表达式树。 这与询问为什么在编译之前无法执行程序没什么不同。
答案 2 :(得分:2)
在C#中,来自C#源代码的“编译代码”是所谓的IL(中间语言)代码。 (这类似于Java字节码。)根据官方标准,它也被称为CIL(通用中间语言)。 (MSIL意思相同,它是微软对CIL的实现。)
当然,运行.NET应用程序时,CLR(公共语言运行时,.NET的虚拟机)将进一步将此IL代码转换为本机代码(机器代码)。 (在某些情况下,IL代码在安装时被编译为本机代码,例如,Windows中的mscorlib.dll
等.NET程序集是预先编译的;这称为NGEN,即本机映像生成。)
当文章提到数据结构时,这意味着表达式树表达式本身不会以相同的方式编译(在应用程序的编译时)IL代码 你的“通常”C#表达或说明。相反,即使在IL代码中,它们仍然是数据(不要忘记:IL代码中的“通常”表达式变为指令,因为它们是由C#编译器翻译的在编译时指导IL代码)。 稍后,可以(明确地)要求编译它们,即在运行时对树进行评估(编译)。在此之前,它们仍然是数据结构。
同一问题的另一种方法:你的C#源代码有一个明确定义的语法,对吧?当您的C#编译器解析并编译它时,它还需要解析所有表达式(“通常”表达式,即忘记表达式树)。例如,当它解析x = y + 5*z;
时,它需要从这些数据构建自己的树,但这只发生在编译时 的C#编译器内部。完成后,例如您的Visual Studio说“构建成功”,然后生成您的IL代码,即您的应用程序已构建。在此构建过程中,C#编译器还使用树和此类结构来表达。
现在,您可以以非常类似的方式查看表达式树:它们表示树结构中的表达式,但这些树在您的应用程序中可用,并且可以在运行时编译(与C#编译器的内部树结构不同) ,在构建应用程序时在内部使用,在构建应用程序后将被丢弃。)
答案 3 :(得分:1)
表达式树(数据结构)可以被认为是关于由lambda或代码表示的代码的元数据。表达式树被编译成可执行代码(lambda)。表达式树是抽象语法树(AST) - 它是一个对象,表示您要执行的代码的结构。 (Ugly Details Here)
所以,为了回答你的问题,表达式树是元数据(我猜你可以考虑数据结构),lambda是可以执行的实际位。
在我看来,Expression Trees的目的不是你引用的文章所保持的。在我看来,Expression Trees允许您在代码中组合lambdas(或代码),以便您的LINQ语句(或其他代码)可以灵活和动态。我不认为它真的归结为通过电线传输你的结构。我想这可以使用它,但在我看来,表达树的一个非常有用的目的是功能代码的组合。
我希望这会有所帮助。
答案 4 :(得分:0)
这两个概念非常明显,并且不清楚你想要比较它们的衡量标准。这就像问苹果与爱情有什么区别......
数据结构是数据建模和存储的概念。
编译代码是一个atrifact,它是编译的结果。
您可以编写实现特定数据结构的代码并对其进行编译。