web-dev-qa-db-ja.com

インターフェイスを明示的または暗黙的に実装することの違いは何ですか?

Visual Studioでは、インターフェイスを右クリックして、[インターフェイスの実装]または[インターフェイスを明示的に実装]を選択できます。

Visual Studio Screenshot

public class Test : ITest
{
    public string Id // Generated by Implement Interface
    {
        get { throw new NotImplementedException(); }
    }

    string ITest.Id // Generated by Implement Interface Explicitly
    {
        get { throw new NotImplementedException(); }
    }
}

2つの違いは、「インターフェイスを明示的に実装する」を選択した場合、作成時にインターフェイス名がインターフェイスのプロパティとメソッドに追加されることだけです。

そのメソッド/プロパティがどこから来たのかを確認できるので、コードが少し読みやすくなりますが、クラスの使用方法やコンパイル方法に違いはありますか?そして、私が暗黙的にまたは明示的に自分のインターフェースを実装するかどうかは本当に重要ですか?

67
Rachel

Andrew Barrett からのトップアンサー の「暗黙的なインターフェイスと明示的なインターフェイスの実装」のSO を確認してください。

基本的に:

  • 暗黙的:インターフェイスのメソッドとプロパティに、クラスの一部であるかのようにアクセスします。
  • 明示的:クラスを実装されたインターフェースとして扱う場合にのみ、メソッドとプロパティにアクセスできます。

コード例:

暗黙:

Test t = new Test();
t.Id; // OK
((ITest)t).Id; // OK

明示的:

Test t = new Test();
t.Id; // Not OK
((ITest)t).Id; // OK

明示的にインターフェイスを実装する必要がある場合、それは、クラスに、インターフェイスのメソッドの1つと同じシグネチャを持つメソッドが既にある場合、またはクラスが、同じシグネチャを持つメソッドを共有する複数のインターフェイスを実装する場合です。しかし、互換性のない契約。

56
Jalayn

メソッドの呼び出し方法にも違いがあります。

explicitインターフェース実装を使用する場合、その特定の実装を呼び出すには、インターフェースタイプを使用する必要があります。

したがって、コードを呼び出す場合、ITest.Idにアクセスするには、ITest型の変数を使用する必要があります。

MSDNの記事 Explicit Interface Implementation(C#Programming Guide) は良い例です。

8
Oded

同じメソッドを定義する2つのインターフェースを実装できます。ただし、明示的にインターフェイスを実装する場合、メソッドにアクセスできるのは、変数がその明示的なインターフェイスに型指定されている場合のみです。

参照: 明示的なインターフェース実装のチュートリアル

4
unholysampler

編集: それは違いを生むべきではない それを行うべきではありませんメンバーにアクセスする前に関連するインターフェースにキャストする必要があるため、クラスが同じプロパティを持つ2つのインターフェースを実装しない限り:

public interface ITest
{
    string Id { get; }
}

public interface IAlsoTest
{
    string Id { get; }
}

public interface ITestToo
{
    int Id { get; }
}

public class Test : ITest, IAlsoTest
{
    // Valid implicit implementation of BOTH interfaces
    public string Id
    {
        get { throw new NotImplementedException(); }
    }
}

public class TestSeparately : ITest, ITestToo
{
    // This way we can do different things depending
    // on which interface the callee called from.
    string ITest.Id
    {
        get { throw new NotImplementedException(); }
    }

    int ITestToo.Id
    {
        get { throw new NotImplementedException(); }
    }
}

public class TestOuch
{
    public void DoStuff()
    {
        var ts = new TestSeparately();

        // Works
        Console.WriteLine(((ITest)ts).Id);

        // Works
        Console.WriteLine(((ITestToo)ts).Id);

        // Not valid! Which one did we want to call?
        Console.WriteLine(ts.Id);
    }
}

使用例は、単一のインターフェイス(常に:Sを忘れます)のみを使用している場合でも、インターフェイスメンバーを明示的に実装すると保持されます。適切なインターフェースにキャストしないでください(かなり混乱します)。

4
Ed James

ジャラヤンの答えに基づいて、

  • 暗黙的:インターフェイスのメソッドとプロパティに、クラスの一部であるかのようにアクセスします。
  • 明示的:クラスを実装されたインターフェースとして扱う場合にのみ、メソッドとプロパティにアクセスできます。

enter image description here