百科问答小站 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也很费劲,,,,




  

相关话题

  c# 双核多线程并行计算 Parallel是不是最优方案? 
  如何看待即将发布的 C# 8.0? 
  除了跨平台和平台成本以外,Java 还有什么特性是 C# 不具备的? 
  为什么Powershell可以在源码中直接调用.NET类,而VBA只能调用.NET DLL? 
  很多人都说 C# 语法怎么优雅,仅仅是因为 C# 的关键字多吗? 
  如何评价 ASP.NET vNext? 
  Html.ActionLink怎么包裹其他代码? 
  如果C#开放了值类型的继承,会有什么问题发生? 
  C#的async和await底层是怎么做到的? 
  .Net源码里,为什么很少见到默认参数? 

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





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