2016-03-26 7 views
1

私はあなたにそれを理解するための最善の試みを行い、私が間違っている場所を教えてくれます。簡単にするために私はLINQの理解に助けが必要です。私の理解はどこが間違っていますか?

、我々は唯一の

  • 番号12345
  • オペレータ%、彼らの通常のprecdenceと>
を持っていることを言葉に住んでいると仮定しましょう

私がしたときに何が起こるか分かりたい

List<int> All = new List<int> { 1, 2, 3, 4, 5 }; 
IEnumerable<int> Filtered = from i in All 
          where i % 2 == 1 
          orderby i descending 
          select i; 
foreach (var i in Filtererd) 
{ 
    Console.WriteLine(i); 
} 

私が最初に理解するのは、クエリ自体がIenumerable<int>を作成しないということです。クエリに関連付けられたExpression Treeが作成されます。クエリによって返される要素は

Source.Reverse()がクエリ自体ですが、とにかく...ので、奇妙な例のようなものだ。当然ながら)

public static IEnumerable<int> MyInvisibleFunction (List<int> Source) 
{ 
    foreach (int i in Source.Reverse()) 
    { 
     if (i % 2 == 1) 
     { 
      yield return i; 
     } 
    } 
} 

のように、コンパイラによって作成された目に見えない機能でyield編です

ここで私は表情の毛皮がここに遊びに来る混乱しています。私が表現した木を考えると、私が作った小さな世界では、

 (3 % 1 > 0) 
     / \ 
     /  \ 
    (3 % 1) > 0 
    / \ 
    3 % 1 

のような木が考えられます。しかし、LINQクエリでは、そのようなツリーが再生されます。

from i in All 
where i % 2 == 1 
orderby i descending 
select i 

???それは私が理解していないものです。私はExpression classを見ていますが、私が示したツリーの例をどのように作成できるかを見ていますが、クエリの中でどこが再生されるのかわかりません。

+2

ソースが通常のメモリ内リストであるため、式ツリーはクエリで機能しません。式ツリーは、ソースがSQLデータベースのようなもので、LINQがクエリをSQLに変換する必要がある場合に便利です。 –

+2

私はLINQについてのあなたの信念に間違っていることをすべて記述することを始める方法もわかりません。それはすべて間違っているので、すべてのものを信じて停止します。私の助言は、C#仕様のコピーを入手し、LINQ変換のセクションを注意深く読んでください。 –

+3

ヒラリー・クリントンは、(布を使って)サーバーを拭くことが意味することさえ知らないので、私はあなたがヒラリークリントンではないと確信しています。あなたのユーザー名は議論されている[ここ](http://meta.stackoverflow.com/questions/319809/what-is-the-policy-on-user-names-that-are-obvious-impersonators-of-actual-人)。個人的には、私はあなたや他の改造者があなたのためにやる前に、あなたのユーザー名を他のものに変更することを検討したいと思います。 –

答えて

8

私はあなたにそれを理解するための最善の試みを行い、私が間違っている場所を教えてくれます。

OK。

私が最初に理解しているのは、クエリ自体がIenumerable<int>を作成しないということです。

このステートメントは完全に間違っています。

クエリに関連付けられた式ツリーが作成されます。

このステートメントも完全に間違っています。クエリによって返さ

要素は、この文はまた、完全に間違っているコンパイラ

によって作成された目に見えない機能で得られたされています。そのような木はそれがない私のLINQクエリ

でプレーするには来るん

。クエリで式ツリーが使用されません。

私はExpressionクラスを見ていると私はそれが私が示した例のツリーを作成することができます方法を見て、それはそれはない遊び

に来るところ私は表示されません。

は私が

List<int> All = new List<int> { 1, 2, 3, 4, 5 }; 
IEnumerable<int> Filtered = from i in All 
         where i % 2 == 1 
         orderby i descending 
         select i; 
foreach (var i in Filtererd) 
    Console.WriteLine(i); 

を行う際の、それを打破してみましょう、何が起こるかdissambleたいです。まず、コンパイラは

List<int> All = new List<int> { 1, 2, 3, 4, 5 }; 
IEnumerable<int> Filtered = All.Where(i => i % 2 == 1).OrderBy(i => i);       
foreach (var i in Filtererd) 
    Console.WriteLine(i); 

次へコンパイラが

List<int> All = new List<int> { 1, 2, 3, 4, 5 }; 
IEnumerable<int> Filtered = 
    Enumerable.OrderBy<int>(
    Enumerable.Where<int>(All, i => i % 2 == 1)), 
    i => i));       
foreach (var i in Filtererd) 
    Console.WriteLine(i); 

次ラムダが脱糖されている拡張メソッドをオーバーロードの解決を行い、評価していることになります:ラムダはありませんどのように実際にある

static bool A1(int i) { return i % 2 == 1;) 
static int A2(int i) { return i } 
... 
List<int> All = new List<int> { 1, 2, 3, 4, 5 }; 
IEnumerable<int> Filtered = 
    Enumerable.OrderBy<int>(
    Enumerable.Where<int>(All, new Func<int, bool>(A1))), 
    new Func<int, int>(A2)));       
foreach (var i in Filtererd) 
    Console.WriteLine(i); 

正確にはdesugared;それらもキャッシュされますが、その詳細を無視してみましょう。

私はforeachをdesugaredしたくないと思います。詳細については、C#の仕様を参照してください。

WhereとOrderByの機能を知りたい場合は、ソースコードをお読みください。

+0

今私たちはラムダがとても甘くて美味しい理由を知っています。いつものように、優れた参考書のMr. Lippert。 –

+3

私はあなたの例で 'OrderByDescending'を使うつもりだと思いますか? –

1

ソースが通常のメモリ内リストであるため、式ツリーはクエリで機能しません。 - Theodoros Chatzigiannakis

これは本当です。

生成される不可視イテレータ関数はありません。クエリの翻訳先:

List<int> All = new List<int> { 1, 2, 3, 4, 5 }; 
IEnumerable<int> Filtered = 
All 
.Where(i => i % 2 == 0) 
.OrderByDescending(i => i); 

カスタムイテレータは必要ありません。言語は単に既存のライブラリ関数を呼び出します。

これは、ラムダ引数は、デリゲートとしてではなく、式ツリーとして渡されていないことを除いてIQueryableでも同じです。

あなたはAsQueryable()コールhereにコメントでこの動作を確認することができます。

+0

ある意味では、*目に見えないイテレータ関数*(その定義を*繰り返す*内部を*繰り返します)、 'WhereSelectEnumerableIterator'があります。しかし、もちろん、Enumerable拡張メソッドは単純なCLRコードであり、 'Queryable'拡張メソッドは、コンパイル/変換できる抽象レイヤーを「何か」に追加するというメッセージです。 –

+2

これは当てはまりますが、C#言語ではクエリがIEnumerableで実行する必要はありません。 yにSelectメソッドがある場合は、xからyからx + 1を選択して書き込むことができます。だから、あなたがそれを検索したいのであれば、Select拡張子を 'bool'に追加することができます。 AFAIKこれは有用なアプリケーションを持っていません。 – usr

+1

また、 'from b in true ...'! – usr