惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

SecWiki News
SecWiki News
量子位
The Cloudflare Blog
美团技术团队
T
The Exploit Database - CXSecurity.com
博客园 - 【当耐特】
Spread Privacy
Spread Privacy
P
Proofpoint News Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 三生石上(FineUI控件)
T
Tor Project blog
博客园 - 司徒正美
宝玉的分享
宝玉的分享
T
Threatpost
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Secure Thoughts
T
Threat Research - Cisco Blogs
Hacker News: Ask HN
Hacker News: Ask HN
Jina AI
Jina AI
博客园 - 聂微东
A
Arctic Wolf
I
Intezer
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Know Your Adversary
Know Your Adversary
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
爱范儿
爱范儿
Hugging Face - Blog
Hugging Face - Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
小众软件
小众软件
T
Tailwind CSS Blog
The Hacker News
The Hacker News
L
LINUX DO - 最新话题
Hacker News - Newest:
Hacker News - Newest: "LLM"
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
TaoSecurity Blog
TaoSecurity Blog
Project Zero
Project Zero
博客园 - 叶小钗
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Cloudbric
Cloudbric
雷峰网
雷峰网
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
大猫的无限游戏
大猫的无限游戏
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Troy Hunt's Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
V2EX - 技术
V2EX - 技术
The GitHub Blog
The GitHub Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Privacy & Cybersecurity Law Blog

博客园 - 海南K.K

海南海口滨海大道洛杉矶城一线海景公寓出售(09年建成,面积88~126平米共六套,一次性团购可打折) 出售海南海口南渡江畔私家别墅(楼高4层,占地388平米,建筑面积570平米) 代友发布:海南海口海景豪宅转让(16层5室3厅3卫2阳台288.0m²) 百度谈人生?别再往自己脸上贴金了! douban api,你到底想做什么? Javascript: 从最受误解的语言,到最流行的语言 LINQ那些事(9)-解析Table<T>.Attach引发的异常和解决方法 你可能不熟悉的CSS 三言二拍:海南的软件业 海口房事:海口纵贯线(-海南购房-海口购房-海南二手房-海口二手房-海南国际旅游岛-养老-过冬-) 海口房事:看京城人争当海南岛民 (-海南购房-海口购房-海南二手房-海口二手房-过冬-养老-国际旅游岛-) 海南海口生态公园公寓出售-海南购房-海口购房-海南二手房-海口二手房-过冬-养老-国际旅游岛- Code4Fun: 通过XML模板系统实现对象的灵活序列化 LINQ那些事儿(5)- 动态查询 LINQ那些事儿(3)- 事务和并发冲突处理 LINQ那些事儿(2)- 简单对象的CRUD操作和Association的级联操作 LINQ那些事儿(1)- 定义从关系数据库到entity class的映射 LINQ那些事 LINQ那些事儿(6)-对象生命周期管理
LINQ那些事儿(4)- Query Expression和Query Operator
海南K.K · 2010-01-01 · via 博客园 - 海南K.K

我学习LINQ的时候是直接看MSDN和LINQ team的blog,经常会被里面的一些名词弄混,下面这些名词你都弄懂了吗?

Expression Tree

Expression

Lambda Expression

Query Expression

Query Operator

Expression Tree

和Expression的区别类似XmlNode和XmlElement的区别。Expression Tree用于表达对IQueryable<T>类型数据源的查询树,是Select/Where/From等多个Query method嵌套,在运行时LINQ2SQL会根据Expression Tree来生成SQL语句。

Expression

确切的说是Expression类,为Expression Tree的每一个节点的基类,并提供了构造不同类型Expression的factory method。在System.Linq.Expression命名空间中提供了多种类型的Expression,经常用到的包括:

Class

Description

BinaryExpression

用来表达所有的二元运算,形式为(left) op (right)。如a+b, c && d等。

UnaryExpression

用来表达所有的一元运算,形式为op(operand)。如!a,b++等。

ConstantExpression

用来表达常量或外部变量(不在Expression Tree的控制结构内定义的变量)的定义。

ParameterExpression

用来表达Expression Tree控制结构内的局部变量的定义

MethodCallExpression

用来表达函数的调用

MemberExpression

用来表达属性的访问

让我们用尝试构造Expression Tree来表达

context.Customers.Where(c => c.City == “London”)

// context.Customers
ConstantExpression customersExpr = Expression.Constant(context.Customers);
// 定义Customer c
ParameterExpression parameterExpr = Expression.Parameter(typeof(Customer), "c");
// 访问c.City属性?
MemberExpression cityExpr = Expression.Property(parameterExpr, "City");
// c.City == "London"
BinaryExpression equalExpr = Expression.Equal(cityExpr, Expression.Constant("London"));
// c => c.City == "London"
LambdaExpression conditionExpr = Expression.Lambda(equalExpr, parameterExpr);

// 注意: Where方法的签名是:
// Queryable.Where<T>(this IQueryable<T> source, Func<T, bool> predicate)
MethodCallExpression methodExpr = Expression.Call(
typeof(Queryable), 
     "Where", 
     new Type[] {typeof(Customer)}, 
     customersExpr, conditionExpr
);

Console.WriteLine(methodExpr.ToString());
// 输出:Table(Customer).Where(c => (c.City = "London"))

另外一个有趣的是,在Queryable的源代码里有不少Expression.Quote()的调用,把a变成’(a)是什么意思? 来看看下面这段代码,分别表示() => 2 + 3和 () => ‘(2 + 3):

BinaryExpression expr = Expression.Add(
Expression.Constant(2), Expression.Constant(3));
var expr1 = Expression.Lambda<Func<int>>(expr);
var expr2 = Expression.Lambda<Func<BinaryExpression>>(Expression.Quote(expr));

Console.WriteLine(expr1.Compile()());  // 输出:5
Console.WriteLine(expr2.Compile()());	 // 输出:(2 + 3)

Quote(A)的意思是,输出值为A表达式,而不是A表达式的计算值。

Lambda Expression

lambda expression可以是Expression Tree的一个节点,可以用来创建一个委托。但你知道如何用lambda expression来创建节点和委托吗?

LambdaExpression expr = () => 2 + 3; 	// 错误
LambdaExpression expr = Expression.Lambda(
Expression.Add(Expression.Constant(2), Expression.Constant(3)))	// 正确,定义节点

Expression<Func<int>> expr = () => 2 + 3;	//正确,定义节点
var expr = Expression.Lambda<Func<int>>(
Expression.Add(Expression.Constant(2), Expression.Constant(3)))	// 正确,定义节点

Func<int> fn = () => 2 + 3;		// 正确,定义委托
Func<int> fn = () => { return 2 + 3; }	//正确,定义委托

这里问个问题,你认为下面的语句1和语句2会导致查询操作有什么区别(输出结果都是6)?答案在“LINQ那些事(8)”。

var context = GenerateContext();
Expression<Func<Customer, bool>> condition = c => c.City == "London";

var result1 = context.Customers.Where(condition);				// 1
var result2 = context.Customers.Where(condition.Compile());		// 2

Console.WriteLine(result1.Count());
Console.WriteLine(result2.Count());

Query Operator

指的是在Enumerable和Queryable类中定义的用于用于对数据进行project/filter操作等的extension method,包括Where/Select/Join/OrderBy/GroupBy等。

Query Expression

刚接触LINQ的时候感觉最特别就是可以用类sql的语句在csharp代码里写查询语句

var result =
from c in context.Customers
where c.City == "London"
select c; 

VS对Query expression提供了诸多支持,包括intelligent sense和编译检查等等。但select和where在IL里是没有,只是compiler在运行时根据query expression转化成对Query operator的调用。但是,并不是所有的query operator在query expression有等价表达,query expression支持的operator只有:

Select/SelectMany/Join/GroupJoin/Where/OrderBy/OrderByDescending/GroupBy/ThenBy/ThenByDescending。

既然query operator是通过extension method的方式提供,这就意味着我们可以通过自己编写extension method,来改变query expression的行为,我们看下面的代码:

public static class QueryOperatorExt
    {
        public static IQueryable<T> Where<T>(
            this IQueryable<T> source, Expression<Func<T, bool>> predicate)
        {
            Console.WriteLine("Calling Where in the customer extension method");

            return Queryable.Where(source, predicate);
        }
}
class Program
    {
        static void Main(string[] args)
        {
            var context = GenerateContext();
            var result =
                from c in context.Customers
                where c.City == "London"
                select c;

            Console.WriteLine(result.Count());
        }
}
// 输出:
Calling Where in the customer extension method
6

参考资料

LINQ和DLR的Expression Tree http://rednaxelafx.javaeye.com/blog/237822

Lambda表达式 http://msdn.microsoft.com/zh-cn/library/bb397687.aspx

表达式目录树 http://msdn.microsoft.com/zh-cn/library/bb397951.aspx

总结:本节讨论了Expression Tree/Expression/Lambda Expression/Query expression/Query Operator的含义和区别,示例了如何构建Expression Tree,正确使用lambda expression,以及如何通过extension method来扩展query expression。

链接

LINQ那些事(总)

1、 LINQ那些事儿(1)- 定义从关系数据库到Entity Class的映射

2、 LINQ那些事儿(2)- 简单对象的CRUD操作和Association的级联操作

3、 LINQ那些事儿(3)- 事务和并发冲突处理

4、 LINQ那些事儿(4)- Query Expression和Query Operator

5、 LINQ那些事儿(5)- 动态查询

6、 LINQ那些事儿(6)- DataContext的对象生命周期管理

7、 LINQ那些事儿(7)- 通过自定义IEnumerable<T>来扩展LINQ

8、LINQ那些事儿(8)- 通过自定义IQueryable<T>和IQueryableProvider来扩展LINQ