为了进一步加深对Lambda表达式的理解,我们需要掌握一个新的知识,Lambda表达式树,可能听名字看起来很高深和难以理解,但实际上理解起来并没有想象中那么难,这篇文章我想分以下几点进行总结。
1,表达式树的语法
2,将代码转换到数据
3,探索表达式树
4,将数据转换到代码
5,IQueryable<T>和表达式树
6,为什么要将LINQ to SQL查询表达式转换成表达式树?
7,IQueryable<T>和IEnumerable<T>
8,总结
//利用Lambda表达式定义一个Func委托 Func<int, int, int> function = (a, b) => a + b;
变量function指向两个数字相加的原生可执行的代码,上面这个Lambda表达式等价于下面这个方法。
public int function(int a, int b) { return a + b; }
这个Lambda表达式和这个方法都可以这样调用。
int c = function(1,2); //结果为:3
表达式树不是一段可执行代码,而是一种数据结构。那么怎么将Lambda表达式转换成表达式树呢?
我们可以使用命名空间System.Linq.Expressions下的Expression类来实现这个需求。
例如我们先创建一个表达式树,如下代码。
//创建表达式树 Expression<Func<int, int, int>> expression = (a, b) => a + b;
这样,我们就创建一个类型为Expression<T>的表达式树,标识expression不是可执行代码;它是一个名叫表达式树的数据结构。我们可以使用工具ExpressionTreeVisualizer来浏览表达式树,如下图。
Expression<TDelegate>类有四个属性:
那么怎么查看表达式树中的参数名称呢?从上图中我们可以看出,参数是一个ReadOnlyCollection集合,所以我们可以通过索引来访问。如下代码。
//访问表达式树的参数 Console.WriteLine("参数1:{0},参数2:{1}",expression.Parameters[0],expression.Parameters[1]);
接下来,怎么查看表达式树的Body体呢?在这个例子里是(a+b)。代码如下。
//访问表达式树的Body BinaryExpression body = expression.Body as BinaryExpression; ParameterExpression left = body.Left as ParameterExpression; ParameterExpression right = body.Right as ParameterExpression; Console.WriteLine(expression.Body); Console.WriteLine(" 表达式左边部分: " + "{0}{4} 节点类型: {1}{4} 表达式右边部分: {2}{4} 类型: {3}{4}", left.Name, body.NodeType, right.Name, body.Type, Environment.NewLine);
输出结果为:
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" alt="" />
通过探索表达式树,我们可以分析表达式的各个部分发现它的组成。你可以看见,我们的表达式的所有元素都展示为像节点这样的数据结构。表达式树是代码转换成的数据。
我们可以将代码转换为数据,那么我们也可将数据转换为代码。下面的代码说明了如果将数据(表达式树数据结构)转换为代码。
//将数据(表达式树)转换为代码 int result = expression.Compile()(1,2); Console.WriteLine(result); //输出结果为:3
可以发现,程序输出结果与Lambda表达式执行结果一样。
现在至少你有一个抽象的概念理解表达式树,现在是时候回来理解其在LINQ中的关键作用了,尤其是在LINQ to SQL中。花点时间考虑这个标准的LINQ to SQL查询表达式:
var query = from c in db.Customers where c.City == "Nantes" select new { c.City, c.CompanyName };
你可能知道,这里LINQ表达式返回的变量query是IQueryable类型。这里是IQueryable类型的定义:
public interface IQueryable : IEnumerable { Type ElementType { get; } Expression Expression { get; } IQueryProvider Provider { get; } }
你可以看见,IQueryable包含一个类型为Expression的属性,Expression是Expression<T>的基类。IQueryable的实例被设计成拥有一个相关的表达式树。它是一个等同于查询表达式中的可执行代码的数据结构。
现在我们知道,表达式树是一个用来表示可执行代码的数据结构。那我们为什么要将LINQ to SQL查询表达式转换成表达式树呢?
一个LINQ to SQL查询不是在C#程序里执行的,而是被转换成SQL语句,通过网络发送,最后在数据库服务器上执行的。也就是说,下面这个LINQ查询不是在C#程序里执行的。
var query = from c in db.Customers where c.City == "Nantes" select new { c.City, c.CompanyName };
它是被转换成SQL语句后在数据库服务器上运行的。转换后的SQL语句如下代码。
SELECT [t0].[City], [t0].[CompanyName] FROM [dbo].[Customers] AS [t0] WHERE [t0].[City] = @p0
现在也许可以回答上面的问题。可以用一句话总结:表达式树是为了更方面地将查询表达式转换成字符串(这里指的是SQL语句)并交给其它程序(这里一般指数据库服务器)执行。
我们知道,LINQ to Objects通常返回IEnumerable<T>,而LINQ to SQL返回的是IQueryable<T>。那为什么它们返回的类型会不一样呢?
我们先来看它们的定义,也许我们可以从它们的定义中找到问题的答案。
IEnumberable<T>的定义如下:
public interface IEnumerable<T> : IEnumerable { IEnumerator<T> GetEnumerator(); }
IQueryable<T>的定义如下:
public interface IQueryable : IEnumerable { Type ElementType { get; } Expression Expression { get; } //表达式树 IQueryProvider Provider { get; } }
可以看出,IQueryable<T>包含一个Expression表达式树的定义而IEnumberable<T>却没有,这同时也揭示了一个现象,表达式树通常用在LINQ to SQL查询中,而LINQ to Objects中却很少使用。
那为什么LINQ to Objects中很少使用表达式树呢?是因为LINQ to Objects查询通常在.net程序中就可以完成,不需要将其转换成字符串(或SQL语句)发送到其它程序中执行。
那么针对这两种返回类型,我们该怎么选择呢?这里有两条原则可以参考:
通过以上内容的学习,发现表达式树并没有想象中那么难以理解,关于表达式树我想用以一几句通俗易懂的话总结。