9

次のコードでコンパイル エラーが発生するのはなぜですか (コメント行を参照)。

    public void Test()
    {
        HashSet<HashSet<Animal>> setWithSets = new HashSet<HashSet<Animal>>();
        HashSet<Cat> cats = new HashSet<Cat>();
        setWithSets.Add(cats); // Compile error
    }

    private class Animal { }

    private class Cat : Animal { }

VS2012 で 2 つのエラーが表示されます。最初のエラーは重要です。

  • エラー 2 引数 1: 'System.Collections.Generic.HashSet<Expenses.Tests.TestDb.SetTest.Cat>' から 'System.Collections.Generic.HashSet<Expenses.Tests.TestDb.SetTest.Animal>' に変換できません
  • エラー 1 'System.Collections.Generic.HashSet<System.Collections.Generic.HashSet<Expenses.Tests.TestDb.SetTest.Animal>>.Add(System.Collections.Generic.HashSet)' に最適なオーバーロードされたメソッドの一致にはいくつかの無効な引数

私の質問は、「setWithSets」に「猫」を追加できないのはなぜですか?

4

4 に答える 4

7

Catから派生したとしても、から派生したというAnimalのは真ではありません。( の唯一の基底クラスはclass です。)HashSet<Cat>HashSet<Animal>HashSet<Anything>object

必要な動作を得るには、HashSet<T>ジェネリック型がその型パラメーターで共変Tである必要があります。しかし、そうではありません。理由は 2 つあります。

  1. C# では、共変または反変にできるのは、ジェネリック インターフェイスとジェネリック デリゲート型のみです。HashSet<>クラスです。
  2. から読み取るだけでなく、追加HashSet<>することもできます(および他のことを行うこともできます)。したがって、共分散は論理的に不可能です。または、a を a と見なして、それに a を追加することもできます。ただし、猫のセットは犬を許可していません。HashSet<Cat>HashSet<Animal>Dog

HashSet<T>たとえばIReadOnlyCollection<T>(.NET 4.5のドキュメント: IReadOnlyCollection<out T>Interfaceを参照)に変更した場合、後者のタイプは (1) インターフェースであり、(2) 読み取りのみを許可し、(3) したがって、"I'mTタイプの作成者が適用することを決定した " の共変。

于 2013-05-31T12:44:59.223 に答える
5

HashSet の型コンストラクターはinvariantであるため、コンパイラ エラーが発生します。

不変という用語の説明については、共分散と反分散をご覧ください。

于 2013-05-31T12:45:48.130 に答える