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

Jav*_*Ros 4 c# linq

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

var query = from p in new Class1<Product>()
        where p.Id == "1000"
        select p
Run Code Online (Sandbox Code Playgroud)

被翻译成:

var query = new Class1<Product>().Where(p => p.Id == "1000").Select(p => p);
Run Code Online (Sandbox Code Playgroud)

然后我实现了我Class1的:

public class Class1<T>
{
    public Class1<T> Where(Expression<Func<T, bool>> expression)
    {
        return this;
    }
    public Class1<T> Select<TResult>(Func<T, TResult> expression)
    {
        return this;
    }
}
Run Code Online (Sandbox Code Playgroud)

我用这段代码测试了它:

static void Main(string[] args)
{
    var query = from p in new Class1<Product>()
                where p.Id == "1000"
                select p;
}
Run Code Online (Sandbox Code Playgroud)

然后我注意到Select没有调用该方法,但是如果我where从LinQ中删除clausule Select则调用:

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

有人知道为什么吗?

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

Jon*_*eet 10

有人知道为什么吗?

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

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

表单的查询表达式

from x in e select v
Run Code Online (Sandbox Code Playgroud)

被翻译成

( e ) . Select ( x => v )
Run Code Online (Sandbox Code Playgroud)

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

( e )
Run Code Online (Sandbox Code Playgroud)

例如

from c in customers.Where(c => c.City == “London”)
select c
Run Code Online (Sandbox Code Playgroud)

简单地翻译成

customers.Where(c => c.City == “London”)
Run Code Online (Sandbox Code Playgroud)

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

表单的查询表达式

from x in e select x
Run Code Online (Sandbox Code Playgroud)

被翻译成

( e ) . Select ( x => x )
Run Code Online (Sandbox Code Playgroud)

这个例子

from c in customers
select c
Run Code Online (Sandbox Code Playgroud)

被翻译成

customers.Select(c => c)
Run Code Online (Sandbox Code Playgroud)

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

  • @EhsanSajjad规范附带Visual Studio ...在默认安装中,您可以在`C:\ Program Files(x86)\ Microsoft Visual Studio <version>\VC#\ Specifications\1033`上找到它们.不确定他们是否在VS 2017上改变了 (2认同)

Ehs*_*jad 6

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

var query = from p in new Class1<Product>()
        where p.Id == "1000"
        select p
Run Code Online (Sandbox Code Playgroud)

将翻译为:

var query = new Class1<Product>().Where(p => p.Id == "1000");
Run Code Online (Sandbox Code Playgroud)

当你删除where部分时:

var query = from p in new Class1<Product>()
            select p;
Run Code Online (Sandbox Code Playgroud)

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

var query = new Class1<Product>().Select(p=>p);
Run Code Online (Sandbox Code Playgroud)


Ren*_*ogt 5

我敢肯定,从查询语法方法的语法翻译优化呼叫Select如果美国离开标识投影.

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

所以

var query = from p in new Class1<Product>()
            where p.Id == "1000"
            select p;
Run Code Online (Sandbox Code Playgroud)

只被翻译成

var query = new Class1<Product>().Where(p => p.Id == "1000");
Run Code Online (Sandbox Code Playgroud)

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