为什么这个 LINQ 查询能够编译?
阅读“奇怪的查询表达式”后作者:Jon Skeet,我尝试了下面的代码。 我预计最后的 LINQ 查询会转换为 int query = proxy.Where(x => x).Select(x => x);
,它不会编译,因为 Where
返回一个 int
。代码编译后将“Where(x => x)”打印到屏幕上,查询设置为 2。 Select 永远不会被调用,但它需要存在才能编译代码。怎么了?
using System;
using System.Linq.Expressions;
public class LinqProxy
{
public Func<Expression<Func<string,string>>,int> Select { get; set; }
public Func<Expression<Func<string,string>>,int> Where { get; set; }
}
class Test
{
static void Main()
{
LinqProxy proxy = new LinqProxy();
proxy.Select = exp =>
{
Console.WriteLine("Select({0})", exp);
return 1;
};
proxy.Where = exp =>
{
Console.WriteLine("Where({0})", exp);
return 2;
};
int query = from x in proxy
where x
select x;
}
}
After reading "Odd query expressions" by Jon Skeet, I tried the code below.
I expected the LINQ query at the end to translate to int query = proxy.Where(x => x).Select(x => x);
which does not compile because Where
returns an int
. The code compiled and prints "Where(x => x)" to the screen and query is set to 2. Select is never called, but it needs to be there for the code to compile. What is happening?
using System;
using System.Linq.Expressions;
public class LinqProxy
{
public Func<Expression<Func<string,string>>,int> Select { get; set; }
public Func<Expression<Func<string,string>>,int> Where { get; set; }
}
class Test
{
static void Main()
{
LinqProxy proxy = new LinqProxy();
proxy.Select = exp =>
{
Console.WriteLine("Select({0})", exp);
return 1;
};
proxy.Where = exp =>
{
Console.WriteLine("Where({0})", exp);
return 2;
};
int query = from x in proxy
where x
select x;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是因为您的“select x”实际上是一个无操作 - 编译器不会费心将
Select(x => x)
调用放在最后。如果您删除where
子句,就会出现这种情况。您当前的查询称为退化查询表达式。有关更多详细信息,请参阅 C# 4 规范的第 7.16.2.3 节。尤其:因此,三个翻译(无论数据源如何)
It's because your "select x" is effectively a no-op - the compiler doesn't bother putting the
Select(x => x)
call at the end. It would if you removed thewhere
clause though. Your current query is known as a degenerate query expression. See section 7.16.2.3 of the C# 4 spec for more details. In particular:So, three translations (regardless of data source)
它可以编译,因为 LINQ 查询语法是词法替换。编译器
只有
然后才检查
Where
和Select
方法是否确实存在于proxy。因此,在您给出的具体示例中,实际上不需要存在
Select
来进行编译。如果你有这样的东西:
那么它会变成:
并且
Select
方法将被调用。It compiles because the LINQ query syntax is a lexical substitution. The compiler turns
into
and only then does it check whether the methods
Where
andSelect
actually exist on the type ofproxy
. Accordingly, in the specific example you gave,Select
does not actually need to exist for this to compile.If you had something like this:
then it would get changed into:
and the
Select
method would be called.