別の答えを追加するのは遅すぎますか?
私は大量のLINQ-to-objectsコードを作成しましたが、少なくともそのドメインでは、より単純なコードを作成する方を使用するために両方の構文を理解するのが良いと主張します-常にドット構文ではありません。
もちろん、ドット構文は時間があるIS進むべき道は-他の人は、これらの例のいくつかを提供しています。しかし、理解力は短期間で変化したと思います-悪いラップが与えられたとしても。したがって、理解が役立つと思われるサンプルを提供します。
数字置換パズルの解決策は次のとおりです(LINQPadを使用して記述されたソリューションですが、コンソールアプリでスタンドアロンにすることもできます)。
// NO
// NO
// NO
//+NO
//===
// OK
var solutions =
from O in Enumerable.Range(1, 8) // 1-9
//.AsQueryable()
from N in Enumerable.Range(1, 8) // 1-9
where O != N
let NO = 10 * N + O
let product = 4 * NO
where product < 100
let K = product % 10
where K != O && K != N && product / 10 == O
select new { N, O, K };
foreach(var i in solutions)
{
Console.WriteLine("N = {0}, O = {1}, K = {2}", i.N, i.O, i.K);
}
//Console.WriteLine("\nsolution expression tree\n" + solutions.Expression);
...出力:
N = 1、O = 6、K = 4
それほど悪くはありませんが、ロジックは直線的に流れており、単一の正しいソリューションが得られることがわかります。このパズルは、手で解決する簡単な十分:3>ことを推論N
> 0、およびO
> 4×N 8> =意味O
10例最大(2手で試験にあります> = 4意味N
行列5のためのO
)。私は十分に迷っています-このパズルはLINQのイラスト目的で提供されています。
コンパイラー変換
これを同等のドット構文に変換するためにコンパイラが行うことはたくさんあります。通常の2番目以降のfrom
句SelectMany
は呼び出しに変換されますが、どちらもtransparent-identifiersを使用する射影付きの呼び出しにlet
なる句Select
があります。これから説明するように、ドット構文でこれらの識別子に名前を付けることは、そのアプローチの可読性を奪います。
このコードをドット構文に変換する際にコンパイラーが行うことを公開するコツがあります。上記の2行のコメントを外し、再度実行すると、次の出力が得られます。
N = 1、O = 6、K = 4
ソリューション式ツリーSystem.Linq.Enumerable + d_ b8.SelectMany(O => Range(1、8)、(O、N)=> new <> f _AnonymousType0 2(O = O, N = N)).Where(<>h__TransparentIdentifier0 => (<>h__TransparentIdentifier0.O != <>h__TransparentIdentifier0.N)).Select(<>h__TransparentIdentifier0 => new <>f__AnonymousType1
2(<> h_ TransparentIdentifier0 = <> h _TransparentIdentifier0、NO = ((10 * <> h_ TransparentIdentifier0.N)+ <> h _TransparentIdentifier0.O)))。Select(<> h_ TransparentIdentifier1 => new <> f _AnonymousType2 2(<>h__TransparentIdentifier1 = <>h__TransparentIdentifier1, product = (4 * <>h__TransparentIdentifier1.NO))).Where(<>h__TransparentIdentifier2 => (<>h__TransparentIdentifier2.product < 100)).Select(<>h__TransparentIdentifier2 => new <>f__AnonymousType3
2(<> h_ TransparentIdentifier2 = <> h _TransparentIdentifier2、K =( <> h_ TransparentIdentifier2.product%10)))。Where(<> h _TransparentIdentifier3 =>(((<> h_ TransparentIdentifier3.K!= <> h _TransparentIdentifier3。<> h_ TransparentIdentifier2。<>h _TransparentIdentifier1。<> h_TransparentIdentifier0.O)AndAlso(<> h _TransparentIdentifier3.K!= <> h_ TransparentIdentifier3。<> h _TransparentIdentifier2。<> h_ TransparentIdentifier1。<> h _TransparentIdentifier0.N))AndAlso((<> h_ TransparentIdentifier3。<> h _TransparentIdentifier3。<> 2。_TransparentIdentifier product / 10)== <> h_ TransparentIdentifier3。<> h _TransparentIdentifier2。<> h_ TransparentIdentifier1。<> h _TransparentIdentifier0.O)))。Select(<> h_ TransparentIdentifier3 => new <> f _AnonymousType4`3(N = < > h_ TransparentIdentifier3。<> h _TransparentIdentifier2。<> h_ TransparentIdentifier1。<> h _TransparentIdentifier0.N、O = <> h_ TransparentIdentifier3。<> h_TransparentIdentifier2。<> h_ TransparentIdentifier1。<> h _TransparentIdentifier0.O、K = <> h__TransparentIdentifier3.K))
各LINQ演算子を新しい行に配置し、「話すことのできない」識別子を「話す」ことができるものに変換し、匿名型を使い慣れた形式に変更し、AndAlso
式ツリーの用語を変更して&&
、コンパイラーが同等の処理に到達するための変換を公開するドット構文で:
var solutions =
Enumerable.Range(1,8) // from O in Enumerable.Range(1,8)
.SelectMany(O => Enumerable.Range(1, 8), (O, N) => new { O = O, N = N }) // from N in Enumerable.Range(1,8)
.Where(temp0 => temp0.O != temp0.N) // where O != N
.Select(temp0 => new { temp0 = temp0, NO = 10 * temp0.N + temp0.O }) // let NO = 10 * N + O
.Select(temp1 => new { temp1 = temp1, product = 4 * temp1.NO }) // let product = 4 * NO
.Where(temp2 => temp2.product < 100) // where product < 100
.Select(temp2 => new { temp2 = temp2, K = temp2.product % 10 }) // let K = product % 10
.Where(temp3 => temp3.K != temp3.temp2.temp1.temp0.O && temp3.K != temp3.temp2.temp1.temp0.N && temp3.temp2.product / 10 == temp3.temp2.temp1.temp0.O)
// where K != O && K != N && product / 10 == O
.Select(temp3 => new { N = temp3.temp2.temp1.temp0.N, O = temp3.temp2.temp1.temp0.O, K = temp3.K });
// select new { N, O, K };
foreach(var i in solutions)
{
Console.WriteLine("N = {0}, O = {1}, K = {2}", i.N, i.O, i.K);
}
実行すると、再び出力されることを確認できます:
N = 1、O = 6、K = 4
...しかし、このようなコードを書くことはありますか?
答えはNONBHN(いいえだけでなく、地獄も違います!)です-それはあまりにも複雑だからです。確かに「temp0」..「temp3」よりも意味のある識別子名を思いつくことができますが、ポイントはコードに何も追加しないということです-コードのパフォーマンスを向上させず、コードを読みやすくするために、彼らはコードをugいだけにし、あなたがそれを手でやっていたら、間違いなくあなたがそれを正しくする前に1、3回混乱させるでしょう。また、「名前ゲーム」をプレイすることは、意味のある識別子にとっては十分に難しいので、コンパイラがクエリの理解で提供してくれる名前ゲームからの脱却を歓迎します。
このパズルのサンプルは、あなたが真剣に考えるほど現実的ではないかもしれません。ただし、クエリの理解が必要な他のシナリオは存在します。
Join
and の複雑さGroupJoin
:クエリ内包join
句の範囲変数のスコープは、そうでなければドット構文でコンパイルされるかもしれない間違いを内包構文のコンパイル時エラーに変えます。
- コンパイラーが内包表記変換に透明識別子を導入するときはいつでも、内包表記は価値があります。これには、複数の
from
句、join
&join..into
句、let
句のいずれかの使用が含まれます。
理解構文を禁止している故郷のエンジニアリングショップを複数知っています。理解構文はツールであり、有用なツールであるため、これは残念だと思います。私はそれは、言ってのようにたくさんだと思う「あなたがノミを行うことができないことをドライバーでできることがあります。あなたはノミのようにドライバーを使用することができますので、ノミは王の法令の下で今後禁止されています。」