web-dev-qa-db-ja.com

ReadOnlyCollectionではなくImmutableListを使用する理由

.NET 4.5には新しい名前空間があります System.Collections.Immutable

このパッケージは、スレッドセーフであり、コンテンツを変更しないことが保証されているコレクション(不変コレクションとも呼ばれます)を提供します。

よくわかりません。 ReadOnlyCollection クラスによってスレッドセーフの問題はすでに解決されていませんか?代わりに ImmutableList を使用するのはなぜですか?


IReadOnlyListinterface もあることを知っています。他のスレッドが別のインターフェイスでオブジェクトを編集する可能性があるため、それは暗黙的にスレッドセーフの問題を解決しません。

51
Colonel Panic

ReadOnlyCollection の場合:

読み取り専用のコレクションは、コレクションの変更を防ぐラッパーを備えた単なるコレクションです。したがって、基になるコレクションに変更が加えられた場合、読み取り専用コレクションにはそれらの変更が反映されます。

これはImmutableListでは起こりえません。

55
James Thorpe

ReadOnlyCollection<T>は、スレッドセーフの問題を解決しません。これは単にIlist<T>のラッパーです。コレクションを変更するメンバーを公開しませんが、基になるコレクション参照を使用していつでも変更できます。

基になるコレクションが変更された場合、ReadOnlyCollection<T>を列挙することは安全ではありません。その場合、「コレクションが変更されました。列挙操作は実行されない可能性があります...」というメッセージで同じInvalidOperationExceptionが返されます。

ReadOnlyCollection<T> から

ReadOnlyCollectionは、コレクションが変更されていない限り、複数のリーダーを同時にサポートできます。それでも、コレクションを介した列挙は本質的にスレッドセーフな手順ではありません。列挙中のスレッドの安全性を保証するために、列挙全体でコレクションをロックできます。読み取りおよび書き込みのために複数のスレッドがコレクションにアクセスできるようにするには、独自の同期を実装する必要があります。

一方、ImmutableListは不変であるため、本質的にスレッドセーフです。

21

ReadOnlyCollectionは、名前が示すとおり、読み取りのみが可能です。

一方、ImmutableList/Add/Removeメソッドを呼び出すことにより、Clearにアイテムを追加/削除できます。新しい不変リストを返します。

17
dcastro

マルチスレッドのシナリオでは、読み取り専用コレクションはまだスレッドセーフではないことに注意してください。

ReadOnlyCollection<T>ドキュメントから:

...基礎となるコレクションに変更が加えられた場合、読み取り専用コレクションはそれらの変更を反映します

List<T>などのコレクションはスレッドセーフではないため、読み取り専用コレクションもスレッドセーフではありません。

重要:MSDNで明確に説明されていないいくつかのコーナーケースがあります。一見コレクションのコンテンツを読み取るだけの操作の一部は、実際にはコレクションの内部構造を変更しています。なぜこれが指定されていないのですか? -明白な理由の1つは、それがAPIに反映されない実装の詳細だからです。その結果、List<T>にラップされたReadOnlyCollection<T>を変更せず、ゲッターのみを使用しても、マルチスレッド環境でクラッシュが発生する可能性があります。

一番下の行は、一般的なコレクションは、ReadOnlyCollectionにラップされていても、そのままマルチスレッド環境で使用できないことです。

ReadOnlyCollectionとは対照的に、不変のコレクションは、コレクションへの参照が取得された後、内部構造が変更されないことを保証します。これらの構造はまだ真に不変ではないことに注意してください。代わりに、freezableです。つまり、構造はfrozenになり、呼び出し元に返されるまで、しばらく内部的に変更されます。そのポイントを超えると、不変コレクションに対する他のすべての呼び出しは、元の参照を介してアクセス可能な構造の外部でのみ変更を行います。

結論:読み取り専用コレクションはnotスレッドセーフです。不変コレクションはスレッドセーフです。

4
Zoran Horvat