1. ホーム
  2. c#

[解決済み] なぜDictionaryにはAddRangeがないのですか?

2022-06-11 03:42:59

質問

タイトルは基本的なものなのに、なぜできないのでしょう。

Dictionary<string, string> dic = new Dictionary<string, string>();
dic.AddRange(MethodThatReturnAnotherDic());

どのように解決するのですか?

元の質問に対するコメントは、このことをよく要約しています。

なぜなら、誰もその機能を設計、指定、実装、テスト、文書化、そして出荷したことがなかったからです。- Gabe Moothart

その理由は?おそらく、辞書をマージする動作は、フレームワークのガイドラインに適合する方法で推論することができないからでしょう。

AddRange は存在しません。なぜなら、データの範囲は重複したエントリを可能にするため、範囲は連想コンテナに何の意味も持たないからです。例えば、もし IEnumerable<KeyValuePair<K,T>> があったとして、そのコレクションは重複したエントリをガードしません。

キーと値のペアのコレクションを追加する動作、あるいは2つの辞書をマージする動作は、単純明快です。しかし、複数の重複するエントリをどのように扱うかという動作はそうではありません。

重複を処理するときのメソッドの動作はどうあるべきでしょうか?

私が思いつく解決策は少なくとも3つあります。

  1. に対して例外を投げる。 最初 のエントリが重複している場合、例外を投げます。
  2. すべての重複するエントリを含む例外をスローします。
  3. 重複を無視する

例外が発生したとき、元の辞書の状態はどうなっているべきでしょうか?

Add はほとんど常にアトミックな操作として実装されます。成功すればコレクションの状態が更新され、失敗すればコレクションの状態は変更されないままです。として AddRange は重複したエラーによって失敗することがあるので、 その挙動を Add との一貫性を保つ方法は、重複した場合に例外を投げることでアトミックにし、元の辞書の状態を変更しないままにすることです。

API の利用者として、重複する要素を繰り返し削除しなければならないのは面倒なことです。 AddRange を含む単一の例外を投げる必要があります。 すべて を含む単一の例外を投げるべきです。

そうすると、選択は以下のようになります。

  1. すべての重複に対して例外をスローし、元の辞書はそのままにします。
  2. 重複を無視して処理を進めます。

両方のユースケースをサポートするための議論があります。そのためには IgnoreDuplicates フラグを署名に追加しますか?

IgnoreDuplicates フラグ (True に設定した場合) は、根本的な実装が重複チェックのコードをバイパスするため、大幅なスピードアップも提供します。

では、フラグを設定することで AddRange をサポートするフラグがありますが、文書化されていない副作用があります (これはフレームワークの設計者が避けるために本当に懸命に努力したことです)。

概要

重複を処理することになると、明確で一貫した期待される動作がないため、一括して処理しない方が簡単で、そもそもメソッドを提供しません。

辞書をマージする必要が常にあることに気付いた場合、もちろん、アプリケーションに適した方法で動作する、辞書をマージする独自の拡張メソッドを書くことができます。