2016-01-13 2 views
5

は、我々は、このインターフェイスに複数の一般的なタイプのために複数回を実装するクラスを作成することができ、以下の共変の汎用インターフェース共変インターフェイスを複数回実装する:この動作は適切に定義されていますか?

public interface IContainer<out T> 
{ 
    T Value { get; } 
} 

を考えます。私が興味を持っているシナリオでは、これらのジェネリック型は共通の基本型を共有しています。タイプIContainer<IPrint>の参照を通じて、このクラスを使用するとき

public interface IPrint 
{ 
    void Print(); 
} 
public class PrintA : IPrint 
{ 
    public void Print() 
    { 
     Console.WriteLine("A"); 
    } 
} 
public class PrintB : IPrint 
{ 
    public void Print() 
    { 
     Console.WriteLine("B"); 
    } 
} 

public class SuperContainer : IContainer<PrintA>, IContainer<PrintB> 
{ 
    PrintA IContainer<PrintA>.Value => new PrintA(); 
    PrintB IContainer<PrintB>.Value => new PrintB(); 
} 

は今、物事は面白く。

public static void Main(string[] args) 
{ 
    IContainer<IPrint> container = new SuperContainer(); 
    container.Value.Print(); 
} 

これは問題なくコンパイルされて実行され、「A」を出力します。私はspecで見つけた:

私は メンバーMが宣言されているインタフェースは、開始、各クラスまたは構造体Sを調べる によって決定される特定のインターフェイスメンバIMの実装Cと、一致が見つかるまで、 ためのCの各連続基本クラスを繰り返す:

  • S は、I及びMと一致する、明示的なインターフェイスメンバーの実装 の宣言が含まれている場合、このメンバーが実装されIM
  • SがMに一致する非静的パブリックメンバ の宣言が含まれている場合そうでない場合、このメンバーはIM

の実装である最初の箇条書きは、インタフェースから、関連するように見えます実装は明示的です。しかし、複数の候補がある場合にどの実装が選択されているかについては何も言及していません。

我々はIContainer<PrintA>実装のための公共popertyを使用する場合には、さらに面白い:上記の仕様によると、今

public class SuperContainer : IContainer<PrintA>, IContainer<PrintB> 
{ 
    public PrintA Value => new PrintA(); 
    PrintB IContainer<PrintB>.Value => new PrintB(); 
} 

IContainer<PrintB>による明示的なインターフェイスの実装がありますので、私は印刷にこれを期待します"B"。ただし、代わりにpublicプロパティを使用して、 "A"を印刷します。

同様に、IContainer<PrintA> explicitlyとIContainer<PrintB>をパブリックプロパティで実装すると、それでも "A"が出力されます。

出力が依存するのは、インターフェイスが宣言されている順序だけです。宣言を

に変更した場合
public class SuperContainer : IContainer<PrintB>, IContainer<PrintA> 

「B」がすべて印刷されます。

仕様が正しく定義されている場合、この動作を定義する仕様の部分はどれですか?

+1

私はそれがどこかで指定されていると思いますが、私はそれを見ていません。 Eric Lippertさんは、[bleg](https://blogs.msdn.microsoft.com/ericlippert/2007/11/09/covariance-and-contravariance-in-c-part-ten-dealing-with-ambiguity/)を持っていました。長い間、誰かがこの問題を考えていました。あなたが派生することができます正確に仕様のどのテキストから –

答えて

0

仕様では見つかりませんが、表示されている内容が必要です。IContainer<PrintA>IContainer<PrintB>は異なる完全修飾名(このFQNが形成される方法に関する仕様を見つけることができません)を有するので、コンパイラは、二つの異なるインターフェースの実装クラスとしてSuperContainer認識し、それぞれがvoid Print();方法を有します。

そこで、我々は、同じシグネチャを持つメソッドを含む二つの異なるインタフェースをそれぞれ有しています。 spec (13.4.2)にリンクすると、最初にIContainer<PrintA>を見て、を探して、Print()の実装が選択されます。IContainer<PrintB>

IContainer<PrintA>に適切なマッピングが見つかったので、SuperContainerの実装がIContainer<PrintB>IContainer<PrintA>.Print()が使用されています。 (一番下に位置する)は同じスペックから

基底クラスのメンバーは、インタフェースマッピングに関与します。例えば

interface Interface1 
{ 
    void F(); 
} 
class Class1 
{ 
    public void F() {} 
    public void G() {} 
} 
class Class2: Class1, Interface1 
{ 
    new public void G() {} 
} 

にクラス1の方法において、Fは、インターフェース1のクラス2の実装に使用されます。

だから、最終的には、そう順序がPrint()メソッドが呼び出されるかを決定しています。

+1

「印刷の実装は、()適切なマッピングを探し、 ''いるIContainer を見て、最初に選択され、_then_ 'いるIContainer 'を見ていますか。」? – Steven

関連する問題