简体   繁体   English

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

[英]Is there a difference between these two statements in Linq?

Is there a difference between these two statements. 这两个语句之间是否有区别。 I did a test, and it failed one of the test on deferred execution. 我做了一个测试,但在延迟执行的测试中,它失败了。 What would be the difference? 有什么区别?

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

and

(from a in items
                where a.Length >= 3
                select a.Substring(0, length)).Distinct();

They read the same to me, and I believe do exactly the same as well? 他们对我读得一样,我相信也完全一样吗?

I'm assuming the 3 vs length is a typo. 我假设3 vs length是错别字。

Once past that, the trick here is: try it ; 过去之后,这里的窍门是: 试试吧 a good tool here is sharplab.io - here's the two examples , and we can see - after compiling and decompiling it - that M and N are about the same: 这里有一个很好的工具Sharplab.io- 这是两个示例 ,在编译和反编译后,我们可以看到MN大致相同:

public void M()
{
    IEnumerable<string> enumerable = Enumerable.Distinct(Enumerable.Select(Enumerable.Where(items, new Func<string, bool>(<M>b__2_0)), new Func<string, string>(<M>b__2_1)));
}

public void N()
{
    IEnumerable<string> enumerable = Enumerable.Distinct(Enumerable.Select(Enumerable.Where(items, new Func<string, bool>(<N>b__3_0)), new Func<string, string>(<N>b__3_1)));
}

They use different compiler-generated methods, but the implementations are the same: 它们使用不同的编译器生成的方法,但实现方式相同:

[CompilerGenerated]
private bool <M>b__2_0(string w)
{
    return w.Length >= length;
}

[CompilerGenerated]
private string <M>b__2_1(string w)
{
    return w.Substring(0, length);
}

[CompilerGenerated]
private bool <N>b__3_0(string a)
{
    return a.Length >= length;
}

[CompilerGenerated]
private string <N>b__3_1(string a)
{
    return a.Substring(0, length);
}

So: we can conclude yes, they're the same. 所以:我们可以得出结论,它们是相同的。

Assuming you meant to write where a.Length >= length , then no. 假设您打算where a.Length >= length写,那么就没有。 The compiler always turns the query syntax into the equivalent syntax using extension methods. 编译器始终使用扩展方法将查询语法转换为等效语法。

You can see that with SharpLab - both of them compile to something which looks like: 您可以通过SharpLab看到它们-它们都可以编译为以下形式:

[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)));
}

You can make use of this equivalence betwen query syntax and extension methods. 您可以在查询语法和扩展方法之间使用这种等效性。 The compiler lets you use the query syntax on types which have extension methods with the right names defined, regardless of whether they're defined on IEnumerable<T> , IQueryable<T> , or anything else. 编译器使您可以对具有扩展名并定义了正确名称的类型使用查询语法,而不管它们是在IEnumerable<T>IQueryable<T>还是其他类型上定义的。

This is an example of "duck typing" in the compiler, where the compiler doesn't care about specific types of interfaces, but only that a certain method with the right name and signature exists at all. 这是编译器中“鸭式输入”的一个示例,其中编译器不关心特定类型的接口,而只是完全存在具有正确名称和签名的特定方法。

For example, this compiles: 例如,这将编译:

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);
    }
}

This is used for example in the Sprache parser combinator library, which lets you write a parser like: 例如,在Sprache解析器组合器库中使用了该库,该库使您可以编写如下解析器:

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());

There's no IEnumerable<T> or IQueryable<T> here - the library just defines the extension methods Select and SelectMany with the right signatures, and the parser happily compiles the above query syntax to use those extension methods. 这里没有IEnumerable<T>IQueryable<T> -库仅使用正确的签名定义扩展方法SelectSelectMany ,并且解析器愉快地编译以上查询语法以使用这些扩展方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM