※ この記事にはアフィリエイトリンクが含まれます
C# の Dictionary の使い方で困っていませんか?
初心者の方は、キーと値の扱いや例外、パフォーマンス面で悩むことが多いです。
- Add 時に同じキーで例外が出るのがわからない
- 存在チェックや安全な取得のやり方が分からない
- 順序が保証されない点でバグを作ってしまう
結論から言うと、Dictionary は高速で便利な連想配列ですが、使い方の基本とよくある落とし穴を押さえれば安全に使えます。
- 基本操作:作成、追加、取得、削除
- 安全な取得:TryGetValue の活用
- パフォーマンスとスレッド安全:容量設定と ConcurrentDictionary の検討
この記事を読むと、Dictionary の基本操作から実践的な注意点、よくあるエラーの対処法まで、現場で役立つ知識を身につけることができます。
実際のコード例やハマりどころも丁寧に解説しますので、初心者でも安心して学べます。
C# Dictionary とは何か?
Dictionary はキーと値のペアを管理するコレクションで、キーから高速に値を取り出せるのが特徴です。
Dictionary の基本概念
キーはユニークでなければならず、同じキーを複数登録しようとすると例外が発生します。
値は任意の型で、null を許容する型かどうかは型に依存します。
基本的な使い方(作成、追加、取得、削除)
ここでは基本的な操作を順を追って確認します。
初めてでも理解しやすいように、コード例を交えて説明します。
作成と追加
// Dictionary の宣言と初期化
var dict = new Dictionary<string, int>();
// 要素の追加(Add)
dict.Add("apple", 100);
dict.Add("banana", 150);
// インデクサを使った追加・更新
dict["orange"] = 120; // 新規追加
dict["apple"] = 110; // 既存キーの値を更新
Add は既に同じキーがあると ArgumentException を投げます。
インデクサ(dict[key])を使うと、存在しなければ追加、存在すれば上書きされます。
取得(安全な方法)
// 安全に値を取得する場合は TryGetValue を使う
if (dict.TryGetValue("banana", out var price))
{
Console.WriteLine($"banana: {price}");
}
else
{
Console.WriteLine("banana は存在しません");
}
// 直接インデクサで取得すると、キーがなければ KeyNotFoundException
var p = dict["grape"]; // 存在しない場合は例外
TryGetValue はキーがない場合に例外を発生させず、効率的にチェックと取得を同時に行えます。
ContainsKey を使ってチェックしてからインデクサで取得するパターンもありますが、TryGetValue の方が冗長さが少なく高速です。
削除と存在確認
// 要素の削除
if (dict.Remove("orange"))
{
Console.WriteLine("orange を削除しました");
}
// キーの存在確認
if (dict.ContainsKey("apple"))
{
Console.WriteLine("apple が存在します");
}
// 全削除
dict.Clear();
よくある迷いとその解決策
初心者がつまずきやすいポイントと、その解決方法を整理します。
簡潔に対処法を示すので、すぐに実践できます。
同じキーを追加して例外が出る
Add で ArgumentException が発生する場合、事前にキーの存在をチェックするか、インデクサで上書きする方法があります。

ただし、存在チェックと追加を分けると並列処理で競合が起きる可能性がある点に注意してください。
- 単一スレッド:
ContainsKey+Addでも問題ない - マルチスレッド:
ConcurrentDictionaryを検討する
列挙中にコレクションが変更される
foreach で Dictionary を回している最中に要素を追加・削除すると InvalidOperationException が発生します。
回避策としては、列挙の前にキーのリストを作るか、変更が必要な項目を別リストにためて処理後に反映します。
// 列挙中に変更したい場合の例
foreach (var key in dict.Keys.ToList())
{
if (ShouldRemove(key))
{
dict.Remove(key);
}
}
パフォーマンスとメモリの注意点
Dictionary は高速ですが、初期容量や再ハッシュによるコストを考慮することが重要です。
大量データを扱う場合は初期容量を指定するとリサイズ回数を減らせます。
初期容量の指定
// 大量要素が分かっている場合は初期容量を指定
var large = new Dictionary<int, string>(capacity: 10000);
容量を超えると内部配列のリサイズがあり、その際にコストが発生します。
頻繁に要素数が増減するケースではメモリと速度のトレードオフを考えてください。
スレッド安全性
標準の Dictionary は単一スレッド向けです。
複数スレッドから同時に読み書きする場合は ConcurrentDictionary を使用するか、外部でロックを行ってください。
// スレッドセーフな ConcurrentDictionary の例
var cd = new System.Collections.Concurrent.ConcurrentDictionary<string, int>();
cd.TryAdd("key", 1);
cd.AddOrUpdate("key", 1, (k, v) => v + 1);
実践的な使い方の例(ユースケース)
ここでは現場でよくあるユースケースと、Dictionary を使うと便利な場面を紹介します。
簡単なコード例で使い方がイメージしやすくなります。
集計処理(頻度カウント)
// 文字列配列の出現回数を数える
var items = new[] { "apple", "banana", "apple", "orange" };
var counts = new Dictionary<string, int>();
foreach (var item in items)
{
if (counts.TryGetValue(item, out var c))
counts[item] = c + 1;
else
counts[item] = 1;
}
// 出力
foreach (var kv in counts)
Console.WriteLine($"{kv.Key}: {kv.Value}");
キーで高速検索するキャッシュ
ID や名前など一意なキーで頻繁に検索するデータは Dictionary に入れておくと高速化できます。
ただし、メモリ使用量と整合性管理を忘れないでください。
よくある質問(FAQ)
最後に、初心者がよく質問するポイントに簡潔に答えます。
実務で遭遇しやすいトラブルを先回りして解説します。
- キーに null を使えるか? 参照型のキーであれば null は許されません。ArgumentNullException が発生します。
- 順序は保証されるか? 標準の Dictionary は順序を保証しません。順序を保持したい場合は OrderedDictionary や List と組み合わせてください。
まとめ
C# の Dictionary は高速で便利なコレクションですが、基本操作と注意点を理解することが重要です。
今回の記事では、作成・追加・取得・削除の基本、TryGetValue の活用、列挙中の変更回避、スレッド安全性やパフォーマンス面の対策を紹介しました。
実践的なサンプルを試して、よくある落とし穴を避けながら使いこなしてみてください。
さらに複雑な要件があれば、ConcurrentDictionary や OrderedDictionary、外部キャッシュの活用も検討しましょう。

エンジニアとして、もっと自分の力を活かしたいあなたへ
「このまま今の職場にいて、成長できるんだろうか?」
C#を使っている方なら、一度はそう感じたことがあるかもしれません。
実は今、C#/.NETエンジニアの市場価値は高まっており、
年収アップ・フルリモート・自社開発企業など、選べる選択肢は確実に増えています。
もし今後、C#を活かして働きたい、あるいは開発現場で経験を積みたいとお考えなら…
自分に合った転職サービスを早めに知っておくことが大きな武器になります。
現役エンジニアからのサポート付き・無料で学べるスクール・社内SE特化の求人など、
転職支援サービスを厳選したまとめ記事をこちらで紹介しています。

ここまで読んでいただきありがとうございました。
コメント