C# Linq中的这两个语句之间有区别吗?

C# Linq中的这两个语句之间有区别吗?,c#,linq,C#,Linq,这两种说法有区别吗。我做了一个测试,其中一个延迟执行测试失败了。有什么区别 items.Where(w => w.Length >= length).Select(w => w.Substring(0, length)).Distinct(); 及 他们给我读了同样的内容,我相信他们也读了同样的内容。我假设3对长度是一个打字错误 一旦超过这一点,这里的诀窍是:尝试一下;这里有一个很好的工具是sharplab.io-,我们可以在编译和反编译后看到,M和N大致相同: 公共空间 {

这两种说法有区别吗。我做了一个测试,其中一个延迟执行测试失败了。有什么区别

items.Where(w => w.Length >= length).Select(w => w.Substring(0, length)).Distinct();

他们给我读了同样的内容,我相信他们也读了同样的内容。

我假设3对长度是一个打字错误

一旦超过这一点,这里的诀窍是:尝试一下;这里有一个很好的工具是sharplab.io-,我们可以在编译和反编译后看到,M和N大致相同:

公共空间 { IEnumerable enumerable=enumerable.DistinctEnumerable.SelectEnumerable.Whereitems,新函数2\u 0,新函数2\u 1; } 公共空间 { IEnumerable enumerable=enumerable.DistinctEnumerable.SelectEnumerable.Whereitems,新函数3\u 0,新函数3\u 1; } 它们使用不同的编译器生成方法,但实现是相同的:

[编译生成] 私有布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔布尔 { 返回w.长度>=长度; } [编译生成] 私有字符串b__2_1字符串w { 返回w.Substring0,长度; } [编译生成] 私人住宅b___3_0字符串a { 返回a.长度>=长度; } [编译生成] 私有字符串b__3_1字符串a { 返回a.Substring0,长度; }
因此:我们可以得出结论:是的,它们是相同的。

假设您打算在a.Length>=Length的地方编写,那么就不是了。编译器总是使用扩展方法将查询语法转换为等效语法

您可以看到,使用-它们都编译成如下内容:

[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
    public int length;

    internal bool <Query>b__0(string a)
    {
        return a.Length >= length;
    }

    internal string <Query>b__1(string a)
    {
        return a.Substring(0, length);
    }
}

public void Query(IEnumerable<string> items, int length)
{
    <>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
    <>c__DisplayClass0_.length = length;
    Enumerable.Distinct(Enumerable.Select(Enumerable.Where(items, new Func<string, bool>(<>c__DisplayClass0_.<Query>b__0)), new Func<string, string>(<>c__DisplayClass0_.<Query>b__1)));
}
您可以利用查询语法和扩展方法之间的这种等价性。编译器允许您对具有定义了正确名称的扩展方法的类型使用查询语法,而不管它们是在IEnumerable、IQueryable还是其他任何类型上定义的

这是一个在编译器中使用duck类型的示例,编译器不关心特定类型的接口,只关心存在具有正确名称和签名的特定方法

例如,这将编译:

public class C {
    public void Query(IThing<string> thing) {
        var y = from x in thing
            select x;
    }
}

public interface IThing<T>
{
    T Foo { get; }   
}

public static class ThingExtensions
{
    public static IThing<T> Select<T>(this IThing<T> thing, Func<IThing<T>, IThing<T>> selector)
    {
        return selector(thing);
    }
}
例如,在parser combinator库中就使用了这种方法,它允许您编写如下解析器:

Parser<string> identifier =
    from leading in Parse.WhiteSpace.Many()
    from first in Parse.Letter.Once()
    from rest in Parse.LetterOrDigit.Many()
    from trailing in Parse.WhiteSpace.Many()
    select new string(first.Concat(rest).ToArray());

这里没有IEnumerable或IQueryable-库只定义了扩展方法Select和SelectMany,并带有正确的签名,解析器很高兴地编译上述查询语法以使用这些扩展方法。

Typo?w=>w.Length>=Length和a.Length>=3如果长度!=3As@DmitryBychenko说,现在这两个是不同的,因为在第一个例子中,你有w.Length>=Length,而在另一个例子中,你有a.Length>=3。您能否澄清一下,您是否希望出现这种差异?最后,问题不是3,而是测试中存在的问题。我两种方法都试过了,最下面的一种给了我一个问题。我想问题是我错过了>=3,这就是我出错的原因
Parser<string> identifier =
    from leading in Parse.WhiteSpace.Many()
    from first in Parse.Letter.Once()
    from rest in Parse.LetterOrDigit.Many()
    from trailing in Parse.WhiteSpace.Many()
    select new string(first.Concat(rest).ToArray());