1. コレクション OrderedDictionary
.NETは昔から標準ライブラリが超充実してるけど、プログラマー人生で「順番を覚えてる辞書が欲しい!」とか「変更できないユニークな値のセットが欲しい!」って時、ちょっと困ったことなかった?.NET 9より前はサードパーティのライブラリ使ったり、自作したり(GitHubからOrderedDictionaryコピペした人もいるよね…しーっ、内緒だよ)。
でも.NET 9からは新しい汎用コレクションが登場!もう変な工夫は不要!今回はその中でも特に使える2つ、OrderedDictionary<TKey, TValue> と ReadOnlySet<T> を詳しく見ていこう。
1. OrderedDictionaryって何?
OrderedDictionaryは辞書とリストのハイブリッド。普通のDictionary<TKey, TValue>みたいに「キーと値」のペアを持つけど、追加した順番を絶対に守ってくれる。ユーザーが入力した順番でデータを処理したい時や、順番がビジネスロジックに影響する(レポート出力、データのシリアライズ、設定ファイルの生成とか)時に超便利!
たとえ話普通の辞書は、物をどこに入れたか気にせずガンガン突っ込めるロッカーみたいなもの。でもOrderedDictionaryは、ちゃんと順番通りに並んでる引き出し付きの棚。何を最初に入れたか、次に何を入れたか、全部わかる!
2. Dictionaryとの主な違い
- Dictionary: 要素の順番は保証されない(たまたま順番通りに見えても、それは幻だから信じちゃダメ!)。
- OrderedDictionary: 追加した順番通りに要素が並ぶ。
3. シンタックスと主なメソッド
基本的な使い方はこんな感じ:
using System.Collections.Generic;
var od = new OrderedDictionary<string, int>();
od.Add("Ivan", 5);
od.Add("Svetlana", 8);
od.Add("Alex", 3);
// 追加した順番でループできる!
foreach (var pair in od)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
出力:
Ivan: 5
Svetlana: 8
Alex: 3
同じ例を普通の辞書でやると、順番がバラバラになることが多い。でもOrderedDictionaryなら、絶対に追加した順番通り!
OrderedDictionaryは普通の辞書と同じインターフェースを実装してるよ:
- IDictionary<TKey, TValue>
- IReadOnlyDictionary<TKey, TValue>
- IEnumerable<KeyValuePair<TKey, TValue>>
4. インデックスとキーでアクセスできる
特徴:OrderedDictionaryはキーだけじゃなく、インデックス(順番)でもアクセスできる!
// 名前(キー)でアクセス:
int svetlanaScore = od["Svetlana"]; // 8
// インデックスでアクセス:
var firstEntry = od.ElementAt(0); // KeyValuePair<string, int>("Ivan", 5)
5. 更新と削除
既存のキーで新しい要素を追加しようとすると例外が出る。値だけ変えたい時はインデクサを使おう:
od["Ivan"] = 10; // 既存の値を変更、順番はそのまま
削除はキーでもインデックスでもできるよ:
od.Remove("Svetlana");
od.RemoveAt(0); // "Ivan"を削除
6. 構造のイメージ
flowchart LR
A("0: Ivan - 5")
B("1: Svetlana - 8")
C("2: Alex - 3")
A --> B --> C
7. よくある落とし穴と注意点
多くの開発者がDictionary<TKey, TValue>で順番を期待しちゃうけど、それは罠!データによっては順番が保たれることもあるけど、.NETのバージョンやプラットフォームが変わると一気に崩れるよ。
OrderedDictionaryは順番を保持する分、挿入や途中削除がちょっとだけ遅いけど、ほとんどのケースではメリットの方が大きい!
インデックスでよく探すならOrderedDictionary、キーだけで高速検索したい&順番どうでもいいなら普通の辞書を使おう。
8. アプリでの実用例
例えば、社員と部署を管理するアプリで、社員を追加した順番でレポートを出したい時:
var employeeScores = new OrderedDictionary<string, int>();
employeeScores.Add("Петр", 100);
employeeScores.Add("Анна", 150);
employeeScores.Add("Виктория", 80);
// レポートはいつも追加順で出力できる!
foreach (var pair in employeeScores)
{
Console.WriteLine($"{pair.Key}: {pair.Value} バロフ");
}
2. コレクション ReadOnlySet<T>
1. ReadOnlySetって何?
ReadOnlySet<T>は変更できない(immutable)ユニークな値のセット。前は「読み取り専用のset」が欲しい時、.ToHashSet()でコピーしたり、自作ラッパーを作ったりしてた。でも今は、一度作ったら追加も削除もできないコレクションがある!これでコードの安全性が上がるし、外部からうっかりデータを変えられる事故も防げるよ。
たとえ話これは、ユニークな名前を書き込んだノートをラミネートしちゃった感じ。もう誰も書き足せないし、破ったり修正もできない!
2. ReadOnlySetの作り方
一番簡単なのは拡張メソッドを使う方法:
var colors = new[] { "Red", "Green", "Blue", "Green" };
var readOnlyColors = colors.ToReadOnlySet();
// ここにはユニークな値だけ、しかも変更不可!
foreach (var color in readOnlyColors)
Console.WriteLine(color);
出力:
Red
Green
Blue
直接コンストラクタを使うこともできる(必要なら):
var set = new ReadOnlySet<int>(new[] {1, 2, 2, 3, 5, 1}); // 結局1,2,3,5だけ
3. 主なプロパティとメソッド
- 読み取り専用(immutable)
- Count ― 要素数
- Contains(item) ― 要素があるかチェック
- LINQクエリ対応(IEnumerable<T>)
- 検索は速いけど、追加・削除・クリアはできない
例:
if (readOnlyColors.Contains("Red"))
Console.WriteLine("赤はリストにあるよ!");
こういうのはできない:
// コンパイルエラー!
readOnlyColors.Add("Yellow");
4. どんな時に使う?
外部にセットを渡したいけど、誰にも中身を変えてほしくない時に超便利。例えば:
- サポートしてるユーザー権限の一覧を返す
- 許可されたファイル拡張子のリスト
- 絶対に変えちゃいけない設定パラメータの一覧
アプリの例:許可された部署の一覧があるとする:
public static ReadOnlySet<string> Departments { get; } =
new[] { "カドリ", "ラズラボトカ", "ブハルテリア" }.ToReadOnlySet();
これで外部から部署リストを勝手に変えられる心配なし!
5. イメージ図:普通のHashSetとの違い
graph LR
A[HashSet] -- Add/Remove/Contains --> B((Elements))
C[ReadOnlySet] -- Only Contains --> D((Elements))
3. OrderedDictionary vs. ReadOnlySet: 違いまとめ表
| コレクション | ペアを持つ? | 順番保証 | 変更できる | キー検索 | インデックス検索 | 用途例 |
|---|---|---|---|---|---|---|
| OrderedDictionary | はい「キー-値」 | はい | はい | はい | はい | マップ、設定、レポート |
| ReadOnlySet | いいえ、値だけ | いいえ | いいえ | はい | いいえ | 安全なセット、定数 |
| HashSet | いいえ、値だけ | いいえ | はい | はい | いいえ | 変更が必要なセット |
| Dictionary | はい「キー-値」 | いいえ | はい | はい | いいえ | 順番不要なマップ |
GO TO FULL VERSION