14

私は次のクラス/インターフェースを持っています:

// Model
public class A : IA { }
// ModelLogic
public class B : IB<A> { }

// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB<T> where T : IA { }

次のコードを使用して新しいインスタンスを作成しようとしています。

IB<IA> foo = new B();

次のエラーが表示されます。

Cannot implicitly convert type 'B' to 'IB<IA>'. An explicit conversion exists (are you missing a cast?)

誰かがなぜこれが不可能なのか説明してもらえますか?

4

3 に答える 3

45

では、 、、 、 、に置き換えてみAましょう。そして、メンバーを に追加し、 の 2 番目の実装を追加します。FishIAIAnimalBAquariumIB<T>IContainer<T>IContainer<T>IAnimal

// Model
public class Fish : IAnimal { }
public class Tiger : IAnimal { }
// ModelLogic
public class Aquarium : IContainer<Fish> 
{ 
    public Fish Contents { get; set; }
}

// Model Interface
public interface IAnimal { }
// ModelLogic Interface
public interface IContainer<T> where T : IAnimal 
{ 
    T Contents { get; set; }
}

IContainer<IAnimal> foo = new Aquarium(); // Why is this illegal?
foo.Contents = new Tiger(); // Because this is legal!

Tiger を foo に入れることができます。foo は、任意の動物を入れることができるコンテナーとして型付けされます。ただし、水族館に入れることができるのは魚だけです。に対して合法的に実行できる操作は、に対して実行できる操作とAquarium異なるIContainer<IAnimal>ため、型には互換性がありません。

必要な機能はジェネリック インターフェイス共分散と呼ばれ、C# 4サポートされていますが、トラを水槽に入れないことをコンパイラに証明する必要があります。あなたがしたいことは次のとおりです。

// Model
public class A : IA { }
// ModelLogic
public class B : IB<A> { }

// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB<out T> where T : IA { }

の共分散注釈に注目してくださいIB。これは、入力としてではなく、出力としてのみ使用できることoutを意味します。が出力のみの場合、「入れる」プロパティまたはメソッドが存在しないため、だれかがトラをその水槽に入れる方法はありません。TT

その機能を C# に追加している間、私はいくつかのブログ記事を書きました。この機能に組み込まれた設計上の考慮事項に興味がある場合は、以下を参照してください。

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/

于 2012-04-27T14:41:16.960 に答える
1

コードを修正するには、変更するだけです

public interface IB<T> where T : IA { }

public interface IB<out T> where T : IA { }
于 2012-04-27T14:43:42.823 に答える
0

空のインターフェイスがある場合、それを確認するのは簡単ではありません。インターフェイス IB に 1 つのメソッド M があるとします。

public interface IB<T> where T : IA 
{ 
    void M(T t); 
}

そして、ここにBの実装があります:

public class B : IB<A>
{
    public void M(A t)
    {
        // only object of type A accepted 
    }
}

次に、IA も実装するオブジェクト C があります。

public class C : IA { } 

したがって、コードが可能であれば、次のように呼び出すことができます。

IB<IA> foo = new B();
foo.M(new C());

問題は、クラス B がタイプ A のオブジェクトしか受け入れないことです。エラー!

于 2012-04-27T14:44:46.230 に答える