How does Linq use IEnumerable methods after IOrderedEnumerable method?

In Linq, extension methods such as Where

return a collection IEnumerable

, but sorting methods such as OrderBy

return a collection IOrderedEnumerable

.

So, if you have a query ending in OrderBy

(i.e. returns IOrderedEnumerable

), you cannot add the method later Where

- the compiler complains about the type being passed to Where

.

var query = Process.GetProcesses()
            .Where(p => p.ProcessName.Length < 10)
            .OrderBy(p => p.Id);

query = query.Where(p => p.ProcessName.Length < 5);

      

However, if you're doing it all in one request, that's great!

var query = Process.GetProcesses()
            .Where(p => p.ProcessName.Length < 10)
            .OrderBy(p => p.Id)
            .Where(p => p.ProcessName.Length < 5);

      

I looked at the assembly in Reflector to see if the compiler had recompiled any operations, but it doesn't seem to be the case. How it works?

+2


source to share


1 answer


IOrderedEnumerable<T>

extends IEnumerable<T>

, so you can still use any of the extension methods. The reason your first block of code didn't work is because you effectively wrote:

IOrderedEnumerable<Process> query = Process.GetProcesses()
                                           .Where(p => p.ProcessName.Length < 10)
                                           .OrderBy(p => p.Id);

// Fail: can't assign an IEnumerable<Process> into a variable 
// of type IOrderedEnumerable<Process>
query = query.Where(p => p.ProcessName.Length < 5);

      

This fails because it query.Where(...)

only returns IEnumerable<Process>

which cannot be assigned to a variable query

. It doesn't cause Where

that the problem is assigning the result back to the original variable. To demonstrate this, this code will work very well:



var query = Process.GetProcesses()
                   .Where(p => p.ProcessName.Length < 10)
                   .OrderBy(p => p.Id);

// Introduce a new variable instead of trying to reuse the previous one
var query2 = query.Where(p => p.ProcessName.Length < 5);

      

Alternatively, you can declare a request IEnumerable<T>

to start with:

IEnumerable<Process> query = Process.GetProcesses()
                                    .Where(p => p.ProcessName.Length < 10)
                                    .OrderBy(p => p.Id);

// Fine
query = query.Where(p => p.ProcessName.Length < 5);

      

+8


source







All Articles