百科问答小站 logo
百科问答小站 font logo



如何对 Expression 进行计算? 第1页

  

user avatar   rednaxelafx 网友的相关建议: 
       @Ivony

大大的回答正解了。

俺就来直接回答一下题主的那几个问题:

其中,当Body == Parameters[0] 时,使用新的ParameterExpression 。
我有三个问题:
1、两者相等意味着什么?为什么这样处理?

并不是Body == Parameters[0],而是Expression<TDelegate>.Body所指向的expression tree中任何节点与这个指定的Parameters[0]相同时,在visitor返回的新expression tree中将这个节点替换为新的ParameterExpression。

这个操作的意思是什么

@Ivony

大大的回答已经说得很清楚了。

expr1与expr2的类型都是Expression<Func<T, bool>>,换句话说这个lambda的函数类型是接受一个类型为T的参数、返回值类型为bool的形式。所以在它们里面肯定只会有1个ParameterExpression,也就是由它们的Parameters[0]所引用的那个。

要提取出expr1与expr2的函数体,将它们组装出一个新的lambda,就必须要把它们的参数替换为新lambda的参数,否则无法建立起新lambda的参数与expr1/expr2已有的函数体之间的联系。

其实要组装expr1与expr2,除了提取出它们的函数体然后直接拼装之外,还可以选择直接调用它们然后组合结果,例如说:

       using System; using System.Linq.Expressions;  static class Program {   static Expression<Func<T, bool>> AndAlso<T>(       this Expression<Func<T, bool>> expr1,       Expression<Func<T, bool>> expr2) {     var param = Expression.Parameter(typeof(T));     var invoke1 = Expression.Invoke(expr1, param);     var invoke2 = Expression.Invoke(expr2, param);     var combine = Expression.AndAlso(invoke1, invoke2);     return Expression.Lambda<Func<T, bool>>(combine, param);   }    static void Main(string[] args) {     Expression<Func<int, bool>> expr1 = a => a >= 0;     Expression<Func<int, bool>> expr2 = b => b < 10;     var combined = expr1.AndAlso(expr2);     var func = combined.Compile();     Console.WriteLine("{0}, {1}", func(2), func(42));     // prints:     // True, False   } }      

这个例子中,

expr1是

       a => a >= 0      

expr2 是

       b => b < 10      

而组合出来的combined的逻辑是:

       x => expr1(x) && expr2(x)      

也就是直接调用expr1与expr2得到结果来做&&操作得到结果(注意这里有短路求值语义喔,虽然这个例子中没有副作用看不出来短路与否的区别)。

而"Invoke",函数调用,用lambda演算的角度来看,就是β-reduction——function application。

expr1(x) ,换个写法就是 (a => a >= 0)(x) ,经过β-reduction之后得到的就是 x >= 0。

对 expr2(x) 如法炮制,(b => b < 10)(x) 应用β-reduction得到 x < 10。

把这俩放在combined中,就变成了:

       x => (x >= 0) && (x < 10)     

可以看到,正如

@Ivony

大大的回答所说,这就是“把函数内联”的效果。

题主所给出的示例代码中,把expr1与expr2的函数体提取出来,并将它们的参数替换为combined的参数,这就是β-reduction。

2、如果我改写成OrElse,这里是不是有影响?

如果您需要的组合方式是 expr1(x) || expr2(x) 的话,那么OrElse()就对了

3、如果想深入学习该方面的知识,有没有推荐的书籍?

这个问题好难回答…其实都是一些编译原理的基本原理的应用,混入一些lambda演算的皮毛。

LINQ Expression Tree / DLR Expression Tree就是一种比较典型的树形/DAG的IR,对它的各种操作都是编译器中端会涉及的知识,所以如果有一些编译原理基础的话学习起来就会很轻松。

不过没有基础也没关系,就是棵表达程序语义的树/DAG而已…

我以前写过一些博客文章跟LINQ与DLR Expression Tree相关,如果有兴趣也可以参考一下:

RednaxelaFX的博客 - DLR分类文章列表 - ITeye技术网站

有本书介绍DLR(与LINQ Expression Tree)的特性和用法的,或许可以参考:

Pro DLR in .NET 4

user avatar   Ivony 网友的相关建议: 
      

简单说就是这样,我们假定有两个函数:

       a => a < 10 b => b > 0     

其中,a和b是

       expr1.Parameters[0] 和 expr2.Parameters[0]      
       a < 10 b > 0      

则是

       expr1.Body 和 expr2.Body      

所以,其实就是产生这样一个东西:

       x =>     //x 就是 parameter = Expression.Parameter(typeof (T));   x < 10 //第一个函数,用x替换了a   &&     //AndAlso   x > 0  //第二个函数,用x替换了b      

就是这个样子:

       x => x < 10 && x > 0      

所以简单说,就是把函数内联。


书籍我自己也想找人给我推荐,我啃DLR也很费劲,,,,




  

相关话题

  为什么大多数解释器都将AST转化成字节码再用虚拟机执行,而不是直接解释AST? 
  C#新启线程导致主线程卡住的问题? 
  为什么.Net托管语言可以实现这些特性? 
  为什么一直没有出现一个可以把现代 CSS 编译为支持老版本浏览器 CSS 的编译工具? 
  为何巴西人能做出 Lua 这种出彩的东西? 
  C# 的扩展方法是否是一个糟糕的设计? 
  用entity framework中查询时,是否有一种表达式最终无法翻译为sql语句? 
  c#表达式目录树的作用是什么?利与弊是什么?应用场景有哪些? 
  C#里面将对象实例赋值为null会否加速GC释放资源? 
  为什么微软建议超过64字节不要使用结构? 

前一个讨论
IE浏览器,为什么低版本不能安装?找不到卸载程序,又无法安装新的低版本,为什么?求指教!?
下一个讨论
vs2015导入失败,提示未能正确加载解决方案中一个或多个项目,怎么解决?





© 2024-11-09 - tinynew.org. All Rights Reserved.
© 2024-11-09 - tinynew.org. 保留所有权利