不使用LinQ查询语法调用Select方法

我想在我的类上启用LinQ查询语法。 我认为查询语法被转换为方法语法,例如:

var query = from p in new Class1() where p.Id == "1000" select p 

被翻译成:

 var query = new Class1().Where(p => p.Id == "1000").Select(p => p); 

然后我将Class1实现为:

 public class Class1 { public Class1 Where(Expression<Func> expression) { return this; } public Class1 Select(Func expression) { return this; } } 

我用这段代码测试了它:

 static void Main(string[] args) { var query = from p in new Class1() where p.Id == "1000" select p; } 

然后我注意到没有调用Select方法,但是如果我删除了来自LinQ Select clausule被调用:

 static void Main(string[] args) { var query = from p in new Class1() // where p.Id == "1000" -> commenting that Select method is called select p; } 

有人知道为什么吗?

这里有一个小提琴,你可以测试它: https : //dotnetfiddle.net/JgxKG9

有人知道为什么吗?

是的,因为这就是语言规范所要做的。 查询表达式转换全部在C#5规范的7.16.2节中。

第7.16.2.5节解释了为什么您的初始示例不正确 – 不会调用Select

表单的查询表达式

 from x in e select v 

被翻译成

 ( e ) . Select ( x => v ) 

除非v是标识符x ,否则翻译很简单

 ( e ) 

例如

 from c in customers.Where(c => c.City == “London”) select c 

简单地翻译成

 customers.Where(c => c.City == “London”) 

但是,7.16.2.3中涵盖的退化查询表达式不是这种情况 – 这解释了删除where子句时会发生什么:

表单的查询表达式

 from x in e select x 

被翻译成

 ( e ) . Select ( x => x ) 

这个例子

 from c in customers select c 

被翻译成

 customers.Select(c => c) 

简并查询表达式是一种简单地选择源元素的表达式 。 翻译的后期阶段通过用其源替换它们来移除由其他翻译步骤引入的简并查询。 但是,重要的是要确保查询表达式的结果永远不是源对象本身,因为这会向查询的客户端显示源的类型和标识。 因此,此步骤通过在源上显式调用Select来保护直接在源代码中编写的简并查询。 然后由Select和其他查询运算符的实现者来确保这些方法永远不会返回源对象本身。

您的理解有点不正确,以下查询:

 var query = from p in new Class1() where p.Id == "1000" select p 

将翻译为:

 var query = new Class1().Where(p => p.Id == "1000"); 

当你删除where部分时:

 var query = from p in new Class1() select p; 

现在它将被翻译成类似的东西:

 var query = new Class1().Select(p=>p); 

我很确定从查询语法到方法语法的转换会优先调用Select away,如果它声明了身份投影

由于p => p会将所有内容投射到自身,并且Where子句已经在源序列和结果之间添加了一个抽象层,因此不再需要此调用。

所以

 var query = from p in new Class1() where p.Id == "1000" select p; 

只被翻译成

 var query = new Class1().Where(p => p.Id == "1000"); 

但我承认我只是猜测,我仍然在寻找相关的规范部分。
更新:乔恩更快