14

C# 4.0 では、ジェネリック型とインターフェイスの co と反変性がさらに拡張されました。一部のインターフェイス ( などIEnumerable<T>) は共変であるため、次のようなことができます。

IEnumerable<object> ie = new List<string>();

しかし、この行はどうですか?コンパイル時エラーが発生しました

List<Object> list = new List<String>();
//Cannot implicitly convert type List<string>' to List<object>'

つまり、List<T>実装する場合、IEnumerable<T>なぜList<T>まだ不変なのですか? これが C# で許可されない理由を説明する良い反例はありますか?

4

2 に答える 2

23

まず、C#ではクラスは常に不変です。次のようなクラスを宣言することはできません。

// Invalid
public class Foo<out T>

第二に、そしてあなたが与えた例にとってより重要なことは、 type の値を受け入れて返すメンバーがList<T>あるため、共変または反変であると宣言することはできませんでした。TT

それ共変であると想像してください。次に、これを書くことができます(明らかなFruitクラス階層のために):

List<Banana> bunchOfBananas = new List<Banana>();
// This would be valid if List<T> were covariant in T
List<Fruit> fruitBowl = bunchOfBananas;
fruitBowl.Add(new Apple());
Banana banana = bunchOfBananas[0];

最後の行は何をすると思いますか? Apple基本的に、実際の実行時の型が であるオブジェクトへの参照を追加することはできませんList<Banana>。バナナの束にリンゴを加えると、りんごが落ちます。私を信じてください、私は試しました。

最後の行は型に関して安全でなければなりません - 内の唯一の値は、またはサブクラスのインスタンスへの参照であるList<Banana>必要があります。nullBanana

クラスが論理的に共変である可能性がある場合でも、クラスが共変になれない理由については...実装レベルで問題が発生し、プログラミングレベルでも非常に制限されると思います。たとえば、次のように考えてください。

public class Foo<out T> // Imagine if this were valid
{
    private T value;

    public T Value { get { return value; } }

    public Foo(T value)
    {
        this.value = value;
    }
}

それはおそらくまだ無効である必要があります-変​​数はまだ書き込み可能です。つまり、「in」スロットとしてカウントされます。タイプのすべての変数をT読み取り専用にする必要があります...そしてそれは初心者向けです。もっと深い問題があるのではないかと強く思います。

純粋なプラグマティズムの観点から言えば、CLR は v2 からのデリゲートとインターフェイスの相違をサポートしています。C# 4 では、この機能を公開するための構文が導入されました。CLR がジェネリック クラスの差異をサポートしたことがあるとは思えません。

于 2012-10-28T07:40:52.690 に答える