2

ソース IEnumerable シーケンスがあるとします。

IEnumerable<Tuple<int, int>> source = new [] {
    new Tuple<int, int>(1, 2),
    new Tuple<int, int>(2, 3),
    new Tuple<int, int>(3, 2),
    new Tuple<int, int>(5, 2),
    new Tuple<int, int>(2, 0),
};

いくつかのフィルターといくつかの変換を適用します。

IEnumerable<int> result1 = source.Where(t => (t.Item1 + t.Item2) % 2 == 0)
                                 .Select(t => t.Item2)
                                 .Select(i => 1 / i);
IEnumerable<int> result2 = from t in source
                           where (t.Item1 + t.Item2) % 2 == 0
                           let i = t.Item2
                           select 1 / i;

これら 2 つのクエリは同等であり、どちらもDivideByZeroException最後の項目に対して をスローします。

ただし、2 番目のクエリが列挙されると、VS デバッガーでクエリ全体を検査できるため、問題の原因を特定するのに非常に便利です。

VSデバッガが便利

ただし、最初のクエリが列挙された場合、同等のヘルプはありません。おそらくバイナリが最適化されているため、LINQ 実装を調べても有用なデータは得られません。

LINQ が最適化されすぎている

IEnumerableクエリ構文を使用していないときに、列挙可能な値を s の「スタック」まで有効に検査する方法はありますか? クエリ構文は、コードを共有できないため、オプションではありません (つまり、変換は重要であり、複数回使用されます)。

4

1 に答える 1

1

ただし、最初のものはデバッグできます。ラムダのいずれかにブレークポイントを挿入するだけで、パラメーターの値やスコープ内にあるものを自由に調べることができます。

ここに画像の説明を入力

Whereデバッグするときは、(最初の 内で壊れている場合) tt.Item1などの値を調べることができます。

ここに画像の説明を入力

t2番目のクエリで最終を実行するときに検査できるがselect、最初のクエリでは検査できない理由については、同等のクエリを作成していないためです。作成した 2 番目のクエリは、コンパイラによって書き出されたときに、最初のクエリのようなものを生成しません。それは微妙に、しかしそれでもかなり異なる何かを生み出します。次のようなものが作成されます。

IEnumerable<int> result1 = source.Where(t => (t.Item1 + t.Item2) % 2 == 0)
                        .Select(t => new
                        {
                            t,
                            i = t.Item2,
                        })
                        .Select(result => 1 / result.i);

呼び出しは、作成した最初のクエリのように、その値を選択するletだけではありません。句から値と前の値を引き出す新しい匿名型を選択しlet、後続のクエリを変更して適切な変数を引き出します。そのため、「前の」変数 (つまりt、クエリの最後にまだスコープ内にあります (コンパイル時と実行時の両方で、それだけでも大きなヒントになるはずです)。上記で提供したクエリを使用すると、 、デバッガーselectを介しての値を確認できます。result.t

于 2013-08-26T17:49:53.747 に答える