非仮想メソッドは静的にバインドされていることを理解しています。つまり、私が理解している限りでは、どのメソッドがどのオブジェクトで呼び出されるかについて、コンパイル時にそれ自体が認識されていることを意味します。この決定は、オブジェクトの静的タイプに基づいて行われます。私を混乱させているのは、( classではなく)インターフェイスと静的バインディングです。
このコードを考えてみましょう。
public interface IA
{
void f();
}
public class A : IA
{
public void f() { Console.WriteLine("A.f()"); }
}
public class B : A
{
public new void f() { Console.WriteLine("B.f()"); }
}
B b = new B();
b.f(); //calls B.f() //Line 1
IA ia = b as IA;
ia.f(); //calls A.f() //Line 2
デモコード: http://ideone.com/JOVmi
を理解していLine 1
ます。コンパイラは、 の静的型が であることを知っているため、b.f()
が呼び出されることを知ることができます。B.f()
b
B
しかし、コンパイラはコンパイル時にどのようia.f()
に を呼び出すかをどのように決定するのA.f()
でしょうか? オブジェクトの静的タイプは何ia
ですか? そうじゃないIA
?しかし、それはインターフェースであり、の定義はありませんf()
。では、なぜそれが機能するのですか?
ケースをより不可解にするために、次のstatic
方法を考えてみましょう。
static void g(IA ia)
{
ia.f(); //What will it call? There can be too many classes implementing IA!
}
コメントにあるように、インターフェイスを実装するクラスが多すぎる可能性があります。その場合、どのメソッドを呼び出すかをIA
コンパイルで静的に決定するにはどうすればよいでしょうか? ia.f()
つまり、次のように定義されたクラスがあるとします。
public class C : A, IA
{
public new void f() { Console.WriteLine("C.f()"); }
}
ご覧のとおりC
、 は とは異なり、からの派生に加えてB
実装しています。つまり、ここでは動作が異なります。IA
A
g(new B()); //inside g(): ia.f() calls A.f() as before!
g(new C()); //inside g(): ia.f() doesn't calls A.f(), rather it calls C.f()
デモコード : http://ideone.com/awCor
これらすべてのバリエーション、特にインターフェイスと静的バインディングがどのように連携するかを理解するにはどうすればよいでしょうか?
さらにいくつか ( ideone ):
C c = new C();
c.f(); //calls C.f()
IA ia = c as IA;
ia.f(); //calls C.f()
A a = c as A;
a.f(); //doesn't call C.f() - instead calls A.f()
IA iaa = a as IA;
iaa.f(); //calls C.f() - not A.f()
これらすべてと、C# コンパイラによって静的バインディングがどのように行われるかを理解するのを手伝ってください。