質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

1320閲覧

ToDictionaryメソッドの引数が1つの構文に関して(拡張メソッド、LINQ to Object)。

退会済みユーザー

退会済みユーザー

総合スコア0

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2019/01/13 12:54

編集2019/01/14 15:47

前提・実現したいこと

こちらのサイトにToDictionaryメソッドの解説がされていますが、
構文と実際に処理しているコードの形式が合わなかったり、説明で分からない点があります。
ご教示お願いします。

試したこと

下記2つのコードが同等であることは、感覚的になんとなく理解できました。

Dictionary<int, Skill> skillDictonary = new Dictionary<int, Skill> (); foreach (Skill skill in skillList) { skillDictionary.Add (skill.Id, skill); }
Dictionary<int, Skill> skillDictonary = skillList.ToDictionary (skill => skill.Id);

この解説がよくわからないです。

ここで使ったオーバーロードは、引数にデリゲートをとります。 IEnumerable<T>の各要素がDictionaryのバリューになります。 引数に渡したデリゲートを、各要素(バリュー)に適用した結果が要素(バリュー)に対応するキーとなります。

引数の「skill => skill.Id」というのはデリゲートなんですか?
また、「引数に渡したデリゲートを、各要素(バリュー)に適用した結果」というのも、どのように適用したのかわからないです。

デリゲートは登録しておいたメソッドを呼び出すものだと認識していましたが、
登録しておいたメソッドはないと思ったからです。

また、下記の構文も
「skillList.ToDictionary (skill => skill.Id);」の形式と全然違うように思えます。

public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector )

例えば、構文だと引数が「TSource, TKey」のようにカンマ区切りで2個与えられていますが、
コードでは、skill => skill.Idの1つの引数を与えていますよね。
また、デリゲートの件と重複しますが、skill => skill.Id がどういう適用になるのかわからないです。
この形式がラムダ式で、「(引数)=>引数を使った処理」という形式なのはわかりますが。

ご教示お願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

この「ぐるぐる回す」というのは、どの記述でわかるものですか?

すみません、半分寝ぼけてたのもあってちょっと誤解を与える記述の仕方でした。

static なメソッドで、第一引数がthis データ型 引数名となっているものは拡張メソッドです。
拡張メソッドの場合、呼び出し元は第一引数自体を引数として渡さずに呼び出します。
この場合のToDictionaryはIEnumerableの拡張メソッドである「LINQ to Object」として提供されています。
こういったLINQ to Objectはいわゆるコレクション変換なので、内部でぐるぐる回しているということになります。

というわけで、「拡張メソッドなので」というより、「LINQ to Objectなので」と書くべきでした。
見たわけではないですが、今回の場合のToDictionaryはこんな感じに内部はなっているはずです。

C#

1public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>( 2 this IEnumerable<TSource> source, 3 Func<TSource, TKey> keySelector) 4{ 5 Dictionary<TKey, TSource> result = new Dictionary<TKey, TSource>(); 6 foreach (TSource value in source) 7 { 8 result.Add(new KeyValuePair( keySelector(value), value)); 9 } 10 return result; 11}

(skill) =>
{
return skill.Id;
}
こちらが、Func<TSource, TKey> keySelectorに該当するということですか?

はい、そうです。
ちなみにラムダ式をFuncデリゲートの一時変数に保管してから渡すとこんな感じになります。

C#

1Func<Skill, int> temp_func = (skill) => skill.Id; 2var skillDictionary = skillList.ToDictionary(temp_func);

投稿2019/01/14 06:29

vo3

総合スコア321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/01/14 15:43

ご回答ありがとうございます。 >static なメソッドで、第一引数がthis データ型 引数名となっているものは拡張メソッドです。 なるほど、拡張メソッドとはそういうものなのですね。 検索して調べました。 メモの為に貼っておきます。 https://webbibouroku.com/Blog/Article/extension-cs また、ToDictionaryは「LINQ to Object」だから、 内部でぐるぐる回しているということなのですね。 理解できました。 ありがとうございました。
guest

0

引数の「skill => skill.Id」というのはデリゲートなんですか?

デリゲートの部分は少し自分でも曖昧なところはあるので恐縮ですがMSDNから

ラムダ式は、 デリゲート型 または 式ツリー型 を作成するために使用できる 匿名関数 です。

とあります。
なので、ラムダ式をデリゲート型に渡していることになります。

次に、引数についてですが

C#

1public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>( 2 this IEnumerable<TSource> source, 3 Func<TSource, TKey> keySelector 4)

Func<TSource, TKey>TSource型の引数を一つ受け取り、TKey型の値を返す デリゲートになります。
で、 skillList.ToDictionary (skill => skill.Id); で渡しているラムダ式の部分はいろいろ省略されている記述なのですが、省略なしで書くと

C#

1skillList.ToDictionary( (skill) => 2 { 3 return skill.Id; 4 });

といった感じになり、これがkeySelectorとして扱われています。

次いでに ToDictionary は拡張メソッドなので、skillListの各要素のIEnumerable<TSource>をぐるぐる回して実行している形になります。

なので、この一行のメソッドをそのまま展開すると、こんな感じになるのだと思います。

C#

1foreach (Skill skill in skillList) 2{ 3 skillDictonary.Add( new KeyValuePair( 4 (skill) => { return skill.Id; }, 5 skill)); 6}

投稿2019/01/13 16:18

編集2019/01/13 16:29
vo3

総合スコア321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/01/14 04:36

ご回答ありがとうございます。 だいぶ全体像が見えました。ありがとうございます。 > ToDictionary は拡張メソッドなので、skillListの各要素のIEnumerable<TSource>をぐるぐる回して この「ぐるぐる回す」というのは、どの記述でわかるものですか? もしくは可能ならばドキュメントでそれが明記されているものを教えていただけますか? それとも、 this IEnumerable<TSource> source, この記述が要素をぐるぐる回すという意味になっていますか? また、念のため確認ですが、 (skill) => { return skill.Id; } こちらが、Func<TSource, TKey> keySelectorに該当するということですか?
vo3

2019/01/14 06:30

> この「ぐるぐる回す」というのは、どの記述でわかるものですか? すみません、半分寝ぼけてたのもあってちょっと誤解を与える記述の仕方でした。 static なメソッドで、第一引数が``this データ型 引数名``となっているものは拡張メソッドです。 拡張メソッドの場合、呼び出し元は第一引数自体を引数として渡さずに呼び出します。 この場合の``ToDictionary``はIEnumerableの拡張メソッドである「LINQ to Object」として提供されています。 こういった``LINQ to Object``はいわゆるコレクション変換なので、内部でぐるぐる回しているということになります。 というわけで、「拡張メソッドなので」というより、「LINQ to Objectなので」と書くべきでした。 見たわけではないですが、今回の場合の``ToDictionary``はこんな感じに内部はなっているはずです。 ``` C# public static Dictionary<TKey, TSource> ToDictionary<TSource, TKey>( this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) { Dictionary<TKey, TSource> result = new Dictionary<TKey, TSource>(); foreach (TSource value in source) { result.Add(new KeyValuePair( keySelector(value), value)); } return result; } ``` > (skill) => > { > return skill.Id; > } > こちらが、Func<TSource, TKey> keySelectorに該当するということですか? はい、そうです。 ちなみにラムダ式をFuncデリゲートの一時変数に保管してから渡すとこんな感じになります。 ``` C# Func<Skill, int> temp_func = (skill) => skill.Id; var skillDictionary = skillList.ToDictionary(temp_func); ```
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問