【C#/Unity】Dictionaryでforeachを使うときに詰まったこと【ゲーム開発】

【C#/Unity】Dictionaryでforeachを使うときに詰まったこと【ゲーム開発】

C#は割と初心者が習得しやすい言語と言われていますが、それでも初心者の頃にいくつか戸惑った点があったので、同じ轍を踏まないように私がちょっと詰まった点を共有させてください。

その詰まった点はDictionaryに関してでした。

DictionaryはListのように複数の値を扱える点は共通していますが、値ごとにキーを設定してアクセスすることができる機能です。このDictionaryでforeachを使う時に「あれ……? どうしたらいいんだろう?」と途方に暮れたので、それを共有させてもらえればと思います。

 

 

Dictionaryとは

C#にはDictionaryという機能があります。これはその名の通り、辞書のようにキーと値をペアで持つことができます。

例えば、

アイテムID 名前
1 ポーション
2 ハイポーション
3 エーテル

のようにアイテムが存在していたとしましょう。

この例だと、アイテムIDがキー、名前が値になっています。これらのデータをDictionaryに追加すると、例えばキーの「1」にアクセスすると「ポーション」の値が取得できるのです。

この時キーの型、値の型を自由に設定できるのが嬉しいところ。以下のようにジェネリックの機能を使って型を指定することができるんです。

例えば一番上の例であれば、アイテムIDと名前のようにintとstringをペアにして値を保持します。私たちが普段、現実世界で使っている辞書のようにstring(項目名)とstring(意味の説明)としてペアを作ることもできますし、ゲームオブジェクトにIDを割り振っておいてint(ID)とGameObject(参照)をペアにして保持することもできます。

個人的にはIDが決まっているデータを扱うことが多く、アイテムデータ用のクラスItemDataを作って、「Dictionary<int, ItemData>」のように辞書を作ることが多いです。

Dictionaryで型を指定する場合は、Listと同じように<>で囲んだ中で型を指定します。型をパラメータとして指定できるジェネリックの機能については以下の記事もご参照くださいな。

 

Dictionaryにデータを追加する

サンプルとして上で紹介したアイテムデータをDictionaryに登録する場合は以下のようになります。

 

あるいは宣言時に初期値をセットすることもできます。

 

例えばアイテムIDが1のアイテム名を知りたい時には、以下のようにアクセスします。[1]のようにアクセスするのは配列でおなじみですね。

 

これを実行すると以下のようにコンソールにアイテム名が表示されます。

アイテム名を取得
アイテム名を取得

 

Dictionaryで困ったこと

さて、やっとこのページの本題です。

Dictionaryでは、foreach文を使って含まれている要素全てにアクセスしたいことがあります。

foreach文といえば、複数の値の集まり(コレクション)の要素を全て確認するのに便利で、例えばint型のリストの中身を全部確認したい場合は以下のように書きます。

 

foreach文の冒頭で宣言しているint型のnumにリストの中の値がどんどん入っていくことによって、リスト内の要素それぞれにアクセスすることができます。

さて、Dictionaryの場合は……。

 

🤔?

型の指定は使う人によって異なるので、何を指定したらいいんでしょうか。中身がint型ならintで指定すればいいのですが、今回紹介したデータはint型とstring型の組み合わせです。

そんな型なんて……あるんです! 実はキーと値のペアをひとつの要素として扱える型を使います。

その名は「KeyValuePair」(キーと値のペア)です。そのまんまで分かりやすいですね。Dictionaryに対してforeach文を使う場合は「KeyValuePair」を使ってペアを作り、そこにDictionaryの値を入れていきます。KeyValuePairでは中身を確認するDictionaryと同じ型を指定します。

 

foreachのループ内でキーを使う場合は「pair.Key」を、値を使う場合は「pair.Value」を使います。(pairの部分は自由な名前を宣言できます)

上のコードを実行すると以下のように辞書の中身が取り出せます。キーとなるアイテムIDや値のアイテム名がちゃんとコンソールに表示されました。

辞書の中身
辞書の中身

 

最初はDictionaryの各要素を表す型が分からず、foreach文だけでなくDictionary自体を使うのをなんとなく避けていました。

しかし実際にサンプルコードを動かしてみたら「意外と難しくないかも?」と思えたので、便利なDictionaryも使ってみてください。

……このページで紹介した私が詰まった部分は「Dictionary foreach」みたいにググれば割とすぐ解決する話ではありますが、コードとにらめっこしてフリーズした経験があったのでついついブログに残してしまいました。私も最初はこういう初歩的な部分でめっちゃつまずいていたんです(まるで今つまずかないかのような言い方)

 

おまけ: Dictionaryのキーの重複や有無を確認

せっかくDictionaryの話が出たので、もう少し深掘りしてキーの重複や、辞書に含まれているかどうかの確認をする方法にも触れてみたいと思います。

Dictionaryではキーを使って値を取得するため、キーが一意(ユニーク: 他とかぶってないこと)である必要があります。

例えば以下のようなコードは実行時にエラーが表示されます。

この例ではエーテルとエクスポーションのキーが両方とも3で重複しているためエラーが発生します。この後の処理は行われないので、ゲーム実行時には重複を検知して回避する必要があります。

キーが辞書に含まれているかどうかを確認するには「ContainsKey()」のメソッドを使います。例えばキーがあるかどうかを調べて、3が存在しなかったらエクスポーション、4が存在しなかったらエリクサーを追加するコードは以下のようになります。

「ContainsKey()」は引数に指定したキーが存在すればtrue、存在しなければfalseを返します。上のコードでは存在しない場合にデータを追加しています。

このまま実行した場合は「3: エーテル」が存在しているのでエクスポーションは追加されず、「4: エリクサー」が追加されます。

エリクサーだけ追加
エリクサーだけ追加

 

辞書のキーを使って値にアクセスする際、存在しないキーを使ってしまうとエラーになってしまうので、事前に「ContainsKey()」を使ってキーがあることを確かめておくのが大切です。

 

まとめ

個人的にC#のDictionaryで戸惑った部分からDictionaryについての簡単な紹介をしました。Dictionaryの中身をforeachで確認する場合はKeyValuePairを使いましょう。

Dictionaryはかなり便利な機能なので、恐れず使いこなせるようになるとプログラミングが楽になります。

 

     

ゲーム開発の攻略チャートを作りました!

CTA-IMAGE

「ゲームを作ってみたいけど、何から手を付けていいか分からない!」


そんなお悩みをお持ちの方向けに、todoがアプリをリリースした経験を中心に、ゲーム作りの手順や考慮すべき点をまとめたe-bookを作成しました。ゲーム作りはそれ自体がゲームのように楽しいプロセスなので、「攻略チャート」と名付けています。


ゲームを作り始めた時にぶつかる壁である「何をしたら良いのか分からない」という悩みを吹き飛ばしましょう!