var q = from t in dict
from v in t.Value.elements
select new { name = t.Key, element = v };
ここでのメソッドはEnumerable.SelectManyです。これらの値が等しいので、あなたはまた、代わりにt.Key
の、上記t.Value.name
を使用することができることを
var q = dict.SelectMany(t => t.Value.elements.Select(v => new { name = t.Key, element = v }));
はEDIT
注:拡張メソッドの構文を使用しました。
ここでは何が起こっていますか?
クエリの理解の構文はおそらく理解しやすいでしょう。あなたは何が起こっているかを見るために同等のイテレータブロックを書くことができます。私たちは、しかし、単に匿名型であることを行うことはできませんので、我々は返すように型を宣言されます:
class NameElement
{
public string name { get; set; }
public string element { get; set; }
}
IEnumerable<NameElement> GetResults(Dictionary<string, MyStruct> dict)
{
foreach (KeyValuePair<string, MyStruct> t in dict)
foreach (string v in t.Value.elements)
yield return new NameElement { name = t.Key, element = v };
}
方法(本当にがここで何が起こっているかまたは、)拡張メソッドの構文の?
(これはhttps://stackoverflow.com/a/2704795/385844でエリックリペットのポストによって部分的に触発され、私はその後、私がいることを読んで、はるかに複雑な説明があったが、この思い付いた:)
我々はNameElementを宣言しないようにしたいとしましょうタイプ。私たちは関数を渡すことによって匿名型を使うことができます。引数リスト(string1, string2)
で定義されて - - と返すラムダ式(string1, string2) => new { name = string1, element = string2 }
は2つの文字列を取る関数を表し
var q = GetResults(dict, (string1, string2) => new { name = string1, element = string2 });
:これまで
var q = GetResults(dict);
:私たちは、このからの呼び出しを変更したいです式new { name = string1, element = string2 }
で定義された文字列で初期化された匿名型のインスタンス。
対応する実装は、このされています
IEnumerable<T> GetResults<T>(
IEnumerable<KeyValuePair<string, MyStruct>> pairs,
Func<string, string, T> resultSelector)
{
foreach (KeyValuePair<string, MyStruct> pair in pairs)
foreach (string e in pair.Value.elements)
yield return resultSelector.Invoke(t.Key, v);
}
型推論私たちは名前でT
を指定せずにこの関数を呼び出すことができます。これは便利です。(C#プログラマとして認識している限り)使用しているタイプには名前がありません:匿名です。変数t
は今pair
ある
注、型パラメータT
との混同を避けるために、そしてv
は「要素」のために、今e
です。また、最初のパラメータの型を基底型の1つ、IEnumerable<KeyValuePair<string, MyStruct>>
に変更しました。それはより洗練されていますが、この方法がより有用になり、最終的に役立ちます。タイプがディクショナリタイプではなくなったので、パラメータの名前をdict
からpairs
に変更しました。
これをさらに一般化することができます。 2番目のforeach
は、キーと値のペアをタイプTのシーケンスに投影する効果があります。その全体の効果は、単一の関数でカプセル化できます。代理人タイプはFunc<KeyValuePair<string, MyStruct>, T>
になります。
IEnumerable<T> GetResults<T>(
IEnumerable<KeyValuePair<string, MyStruct>> pairs,
Func<string, string, T> resultSelector)
{
foreach (KeyValuePair<string, MyStruct> pair in pairs)
foreach (T result in pair.Value.elements.Select(e => resultSelector.Invoke(pair.Key, e))
yield return result;
}
今、私たちは簡単に署名を変更することができます:
最初のステップは、私たちが
resultSelector
デリゲートを呼び出すために
Select
方法を使用して、シーケンスに要素
pair
を変換し、単一の文を持っているので、メソッドをリファクタリングすることです
IEnumerable<T> GetResults<T>(
IEnumerable<KeyValuePair<string, MyStruct>> pairs,
Func<KeyValuePair<string, MyStruct>, IEnumerable<T>> resultSelector)
{
foreach (KeyValuePair<string, MyStruct> pair in pairs)
foreach (T result in resultSelector.Invoke(pair))
yield return result;
}
コールサイトは次のようになりました。ラムダ式は、今はその署名を変更したときに、我々はメソッド本体から取り外しロジック組み込んでどのように気付か:(以下冗長とその実装)メソッドは、より便利にするために
var q = GetResults(dict, pair => pair.Value.elements.Select(e => new { name = pair.Key, element = e }));
を、のとタイプKeyValuePair<string, MyStruct>
に代わっ型パラメータ、TSource
。私たちは、同時にいくつかの他の名前に変更されます:
T -> TResult
pairs -> sourceSequence
pair -> sourceElement
をそして、ちょうど蹴りのために、我々は、拡張メソッドを作ってあげる:
static IEnumerable<TResult> GetResults<TSource, TResult>(
this IEnumerable<TSource> sourceSequence,
Func<TSource, IEnumerable<TResult>> resultSelector)
{
foreach (TSource sourceElement in sourceSequence)
foreach (T result in resultSelector.Invoke(pair))
yield return result;
}
そしてそこにあなたがそれを持っている:SelectMany!さて、この関数の名前はまだ間違っています。実際の実装には、ソースシーケンスとセレクタ関数がnullではないという検証が含まれていますが、それがコアロジックです。
からMSDN:SelectMany
"は、シーケンスの各要素をIEnumerableに投影し、結果のシーケンスを1つのシーケンスにフラット化します。
あなたは正しく注意として出力はC OUT、確かに、辞書に格納(とされなければならないことを規定していません注釈してください)。 – phoog
@phoogあなたは正しいです。私は誤解する。だから私は私のコメントを削除しました。 – sinanakyazici
何らかの理由で@sinanakyazici私の電話のブラウザで私のコメントを削除(また編集)できません:( – phoog