10

出力:
B->こんにちは! 明示的から。

そうではありませんか?
A→こんにちは!明示的から。

明示的なキャスト (IHello) がクラス A から IHello.Hello() を呼び出さないのはなぜですか?

interface IHello
{
    void Hello();
}

class A : IHello
{

    public virtual void Hello()
    {
        Console.WriteLine("A->Hello!");
    }

    void IHello.Hello()
    {
        Console.WriteLine("A->Hello! from Explicit.");
    }
}

class B : A, IHello
{
    public override void Hello()
    {
        Console.WriteLine("B->Hello!");
    }

    void IHello.Hello()
    {
        Console.WriteLine("B->Hello! from Explicit.");
    }
}

class Program
{
    static void Main(string[] args)
    {
        A a = new B();
        ((IHello)a).Hello();
    }
}
4

4 に答える 4

21

いいえ、そうすべきではありません。

への呼び出しHelloは、コメントアウトされたものと同等です - を取得するためのルートは重要でIHelloはありません (実行時のチェックまたは変換が必要でない限り)。コンパイル時の型はIHelloどちらの方法でもかまいません。インターフェースのマッピングは同じですが、そこにたどり着きます。

インターフェイスが型階層で複数回明示的に実装されている場合は、最も派生した型の実装が使用されます。(インターフェイス経由で呼び出された場合。)

C# 3.0 仕様のセクション 13.4.4 から:

クラスまたは構造体 C のインターフェイス マッピングは、C の基本クラス リストで指定された各インターフェイスの各メンバーの実装を検索します。特定のインターフェイス メンバー IM の実装が決定されます。ここで、I はメンバー M が宣言されているインターフェイスです。各クラスまたは構造体 S を調べ、C から始めて、一致するものが見つかるまで、C の連続する各基本クラスに対して繰り返します。

  • S に、I および M と一致する明示的なインターフェイス メンバー実装の宣言が含まれている場合、このメンバーは IM の実装です。
  • それ以外の場合、S に M に一致する非静的パブリック メンバーの宣言が含まれている場合、このメンバーは IM の実装です。複数のメンバーが一致する場合、どのメンバーが IM の実装であるかは指定されていません。この状況は、S が次の場合にのみ発生する可能性があります。は、ジェネリック型で宣言された 2 つのメンバーが異なるシグネチャを持つ構築型ですが、型引数によってそれらのシグネチャが同一になります。
于 2009-12-06T20:38:10.083 に答える
3

(A)a は何もしません。参照はすでに として宣言されているため、 A にキャストしても効果はありません。

参照が A として宣言されていても、それが参照するオブジェクトの型は B です。このオブジェクトを IHello にキャストすると、Hello() を呼び出すと、オブジェクト B の Hello の明示的な実装が呼び出されます。

出力は期待どおりです。

于 2009-12-06T20:41:00.050 に答える
0

いいえ、そうすべきではありません。

仮想メソッドを呼び出す場合、参照の型は関係ありません。呼び出されるメソッドは、参照の型ではなく、オブジェクトの実際の型によって決まります。

クラスのインスタンスを作成するBと、オブジェクトの実際の型は になりますB。表示される理由は、クラス"This is class A."のメソッドをオーバーライドしていないためです。キーワードを使用してシャドウしています。したがって、クラスには 2 つのメソッドがあり、1 つはクラスから継承され、もう 1 つはクラスをシャドウします。参照を使用してメソッドを呼び出すと、継承されたメソッドが呼び出されますが、参照を使用して呼び出すと、シャドウ メソッドが呼び出され、.ToStringBnewBToStringAAToStringB"This is class B."

また、メソッドをシャドウするのではなくToStringクラスでオーバーライドすると、参照のタイプに関係なく出力されます。B"This is class B."

于 2009-12-06T20:46:24.590 に答える
0

いいえ、新しいメソッド (ToString) を作成するとき、それは仮想ではありません。新しいとは、基本クラスのバージョンを「非表示」にしてもかまわないことを意味するだけです。そのため、特定の型 (A) にキャストした参照を使用して呼び出すと、クラス A のメソッドが実行されます。呼び出しているオブジェクトの実際の型。(つまり、A.ToString() を呼び出したので、A.ToString() を実行しました)

仮想メソッドを作成すると、参照をキャストする型に関係なく、オブジェクトの実際の型からの実装が使用されます (つまり、B を作成したので、呼び出したときに (オブジェクトが何であれ)) こんにちは、それはB.Helloと呼ばれる)

重要な違いは、1 つの呼び出しが仮想で、もう 1 つの呼び出しが非仮想であるということです。

于 2009-12-06T20:39:54.420 に答える