9

このコードが機能する理由は、Enumeratorがコレクションを変更できないためです。

var roList = new List<string>() { "One", "Two", "Three" };
IEnumerable<object> objEnum = roList;

List<object>の代わりに, を使用して同じことを行おうとすると、暗黙的に型を にIEnumerable<object>変換できないというコンパイラ エラーが発生します。わかりました、それは理にかなっており、私の意見では、配列から学んだ教訓として、Microsoft による良い決定でした。 List<string>List<object>

しかし、私が理解できないのは、なぜ世界でこの強硬なルールが次のようなものに適用されるのReadOnlyCollectionですか? の要素を変更することはできません。ReadOnlyCollectionでは、Microsoft が読み取り専用のもので共分散を使用することを妨げた原因となった安全上の懸念は何ですか? ポインターなどを使用して、Microsoft が説明しようとしていたそのタイプのコレクションを変更する方法はありますか?

4

1 に答える 1

10

分散と反分散は、クラスではなく、インターフェイスとデリゲートでのみ機能します。

ただし、それを行うことができます (.NET 4.5 を使用):

ReadOnlyCollection<string> roList = ...
IReadOnlyCollection<object> objects = roList;

(IReadOnlyCollection<T>共変なので)


クラスで分散が許可されない理由についての質問に答えるために、Jon Skeet のC# in Depthの本 (第 2 版、§13.3.5、394 ページ) からの説明を次に示します。

クラス内の型パラメーターの差異なし

バリアント型パラメーターを持つことができるのは、インターフェイスとデリゲートのみです。type パラメーターを入力にのみ使用する (または出力にのみ使用する) クラスがある場合でも、inorout 修飾子を指定することはできません。たとえばComparer<T>、 の一般的な実装 IComparer<T>は不変です。 から Comparer<IShape>への変換はありませんComparer<Circle>

これにより発生した可能性のある実装上の問題は別として、概念的にはある程度理にかなっていると思います。インターフェイスは特定の観点からオブジェクトを見る方法を表しますが、クラスはオブジェクトの実際の型に根ざしています。確かに、この引数は、オブジェクトをその継承階層内の任意のクラスのインスタンスとして扱うことができる継承によって多少弱められています。いずれにせよ、CLR はそれを許可しません。

于 2014-08-29T20:41:09.037 に答える