简体   繁体   中英

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.

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:

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. 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:

[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.

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:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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