3

Linqでは、拡張メソッドWhereはコレクションを返しIEnumerableますが、並べ替えメソッドOrderByはコレクションを返しIOrderedEnumerableます。

したがって、で終わるOrderBy(つまり、を返すIOrderedEnumerable)クエリがある場合、後でメソッドを追加することはできません。Whereコンパイラは、に渡される型について文句を言いWhereます。

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

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

ただし、すべてを1つのクエリで実行する場合は、問題ありません。

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

Reflectorでアセンブリを調べて、コンパイラがいずれかの操作を並べ替えているかどうかを確認しましたが、そうではないようです。これはどのように作動しますか?

4

1 に答える 1

9

IOrderedEnumerable<T>拡張IEnumerable<T>するので、拡張メソッドを引き続き使用できます。コードの最初のブロックが機能しなかった理由は、効果的に次のように記述したためです。

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

変数に割り当てることができないquery.Where(...)のみを返すため、これは失敗します。問題は呼び出しではありません。結果を元の変数に代入しています。それを実証するために、このコードは問題なく動作します。IEnumerable<Process>queryWhere

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

IEnumerable<T>または、最初にクエリを宣言することもできます。

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

// Fine
query = query.Where(p => p.ProcessName.Length < 5);
于 2009-10-13T09:32:07.900 に答える