17

ICollection<T>.IsReadOnlyクラスからプロパティの明示的なインターフェイス実装をオーバーライドしようとしているときに、明示的なインターフェイス メンバーの実装は、またはCollection<T>などの修飾子を持つことができないため、オーバーライドできないと述べているドキュメントに出くわしました。MSDNでは、明示的なインターフェイス メンバーの実装によって呼び出される別の抽象メンバーまたは仮想メンバーを作成することによって、明示的なインターフェイス メンバーの実装を継承できるようにする方法を指定するところまで行っていますこれまでのところ問題はありません。virtualabstract

しかし、私は疑問に思います: C# では、インターフェイスを明示的に指定するだけで、明示的に実装されたインターフェイス メンバーをオーバーライドできるのはなぜですか?

たとえば、プロパティとメソッドを使用して、次のような単純なインターフェイスがあるとします。

public interface IMyInterface
{
    bool AlwaysFalse { get; }
    bool IsTrue(bool value);
}

また、Aインターフェイスを明示的に実装しTest()、独自のインターフェイス メンバー実装を呼び出すメソッドを持つクラス。

public class A : IMyInterface
{
    bool IMyInterface.AlwaysFalse
    { get { return false; } }

    bool IMyInterface.IsTrue(bool value)
    { return value; }

    public bool Test()
    { return ((IMyInterface)this).AlwaysFalse; }
}

ご覧のとおり、4 つのメンバーはいずれも仮想または抽象ではないため、次のBようなクラスを定義すると、次のようになります。

public class B : A
{
    public bool AlwaysFalse
    { get { return true; } }

    public bool IsTrue(bool value)
    { return !value; }
}

B次に、キャスト toのインスタンスが のAように動作することを期待しますA。そしてそれは:

A a = new A();
Console.WriteLine(((IMyInterface)a).AlwaysFalse);    // False
Console.WriteLine(((IMyInterface)a).IsTrue(false));  // False
Console.WriteLine(a.Test());                         // False
A b = new B();
Console.WriteLine(((IMyInterface)b).AlwaysFalse);    // False
Console.WriteLine(((IMyInterface)b).IsTrue(false));  // False
Console.WriteLine(b.Test());                         // False

今、キャッチが来ます。クラス宣言の 1 つの点を除いてC、完全なコピーであるクラスを作成します。B

public class C : A, IMyInterface
{ /* ... same as B ... */ }

のインスタンスがCにキャストされると、 のAように動作するのではなく、 のように動作するようになりAましたC

A c = new C();
Console.WriteLine(((IMyInterface)c).AlwaysFalse);    // True
Console.WriteLine(((IMyInterface)c).IsTrue(false));  // True
Console.WriteLine(c.Test());                         // True

メソッドでさえ、Test()オーバーライドされたメソッドをC!で呼び出すようになりました。どうしてこれなの?

4

1 に答える 1

11

これは、明示的なインターフェイスの実装とは何の関係もありません。これは、継承とインターフェイスマッピングの一般的なルールの結果にすぎません。型が明示的ではなく暗黙的な実装を提供した場合、まったく同じ結果が表示されます。AIMyInterface

  • タイプはタイプBから継承しAます。何も上書きされません。
    B独自のメンバーを提供しますAlwaysFalseIsTrue、実装しませんIMyInterface。の実装は、:IMyInterfaceから継承されたメンバーによって提供されAます。型のインスタンスBがキャストされると、インターフェイスを実装するメンバーを提供するためIMyInterface、型のインスタンスとまったく同じように動作します。AA
  • タイプはタイプCから継承しAます。繰り返しますが、何もオーバーライドされません。
    C独自のメンバーAlwaysFalseIsTrueメンバーを提供しますが、今回はそれらのメンバー実装IMyInterfaceします。タイプのインスタンスCがキャストされるとIMyInterface、のメンバーではCなく、のメンバーがインターフェイスの実装を提供しますA

typeは明示的にA実装するため、コンパイラは;のメンバーとIMyInterfaceのメンバーを非表示にしていることを警告しません。事実上、これらのメンバーは、明示的なインターフェースの実装のためにすでに非表示になっています。BCAA

明示的にではなく暗黙的Aに実装するように型を変更した場合、コンパイラは、とのメンバーがのメンバーをオーバーライドするのではなく非表示にしていること、およびのメンバーを宣言するときに修飾子を使用する必要があることを警告します。IMyInterfaceBCAnewBC

言語仕様からのいくつかの関連するビットはここにあります。(ECMA-334仕様のセクション20.4.2および20.4.4、 Microsoft C#4仕様のセクション13.4.4および13.4.6 。)

20.4.2インターフェースマッピング

I.M特定のインターフェイスメンバーの実装(はI、メンバーM が宣言されているインターフェイス)は、各クラスまたは構造体を調べて、一致するものが見つかるまで、の連続する基本クラスごとSに開始して繰り返すことによって決定されます。CC

20.4.4インターフェースの再実装

インターフェイスの実装を継承するクラス は、基本クラスリストに含めることでインターフェイスを再実装できます。インターフェイスの再実装は、インターフェイスの最初の実装とまったく同じインターフェイスマッピングルールに従います。したがって、継承されたインターフェイスマッピングは、インターフェイスの再実装のために確立されたインターフェイスマッピングにはまったく影響しません。

于 2010-09-14T06:38:59.970 に答える