4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

IReadOnlyList<T>とIReadOnlyCollection<T>とReadOnlyCollection<T>

Last updated at Posted at 2023-05-14

たまに触るとIReadOnlyList<T>IReadOnlyCollection<T>ReadOnlyCollection<T>の関係を忘れてしまうので、メモです。

ReadOnlyCollection<T>

そもそもReadOnlyCollection<T>クラスのネーミングが悪い気がしますが、これはIReadOnlyCollection<T>インターフェイスとセットのクラスではありません。ドキュメントを見れば一目瞭然ですが、これはIReadOnlyCollection<T>だけでなく、IReadOnlyList<T>も実装しています。

IReadOnlyCollection<T>とIReadOnlyList<T>の違いはインデクサーの有無で、IReadOnlyCollection<T>にはインデクサーはないのに、ReadOnlyCollection<T>にはインデクサーがあるので混乱しますが、そもそもReadOnlyCollection<T>はIReadOnlyCollection<T>用とIReadOnlyList<T>用のクラスを兼ねていて、どちらのインターフェイスでアクセスするかでインデクサーへのアクセス可否が変わるというだけということです。

これはドキュメントに当たればすぐに分かる話ですが、得てしてコードをいじっているだけでは、ReadOnlyList<T>というクラスがないこと、List用のList<T>.AsReadOnly()メソッドも、Array用のArray.AsReadOnly<T>(T[])メソッドも生成されるのはReadOnlyCollection<T>ということの理由にたどり着かないのですよね。

Dictionary<TKey, TValue>のReadOnly化

Dictionary<TKey, TValue>からReadOnlyDictionary<TKey, TValue>クラスをコンストラクターで生成した場合、TValueがListやArrayなどのコレクションの場合、そのままではコレクションの要素は当然ReadOnlyにはなりません。したがって、一旦TValueをReadOnlyCollection<T>に変換した上で、インデクサーの必要性に応じてIReadOnlyList<T>かIReadOnlyCollection<T>にキャストする必要があります。

Listの場合

var d1 = new Dictionary<string, List<int>>();
...
IReadOnlyDictionary<string, IReadOnlyList<int>> d2 =
    new ReadOnlyDictionary<string, IReadOnlyList<int>>(d1.ToDictionary(
        x => x.Key,
        x => (IReadOnlyList<int>)x.Value.AsReadOnly()));
var d1 = new Dictionary<string, List<int>>();
...
IReadOnlyDictionary<string, IReadOnlyCollection<int>> d2 =
    new ReadOnlyDictionary<string, IReadOnlyCollection<int>>(d1.ToDictionary(
        x => x.Key,
        x => (IReadOnlyCollection<int>)x.Value.AsReadOnly()));

Arrayの場合

var d1 = new Dictionary<string, int[]>();
...
IReadOnlyDictionary<string, IReadOnlyList<int>> d2 = 
    new ReadOnlyDictionary<string, IReadOnlyList<int>>(d1.ToDictionary(
        x => x.Key,
        x => (IReadOnlyList<int>)Array.AsReadOnly(x.Value)));
var d1 = new Dictionary<string, int[]>();
...
IReadOnlyDictionary<string, IReadOnlyCollection<int>> d2 = 
    new ReadOnlyDictionary<string, IReadOnlyCollection<int>>(d1.ToDictionary(
        x => x.Key,
        x => (IReadOnlyCollection<int>)Array.AsReadOnly(x.Value)));

やや面倒ですが、こんな感じかと思います。なお、TValueがNullの可能性がある場合は、ReadOnlyCollection<T>に変換する前にNullチェックも必要になります。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?