オーバーライドされた仮想メソッドが、それをオーバーライドするクラスではなく、それを導入するクラスに属していることを理解すると、クラス メンバーがバインドされる方法を理解しやすくなります。オブジェクトを使用する場合を除きdynamic、C# のすべてのバインドはコンパイル時に解決されます。aBaseClassが仮想メソッドを宣言しfoo、 をDerivedClass:BaseClassオーバーライドする場合、型の変数fooを呼び出そうとするコードは常に仮想メソッド "slot" にバインドされ、それが実際のメソッドを指します。fooBaseClassBaseClass.fooDerivedClass.foo
C# では、C++ とは異なり、ジェネリック型のメンバーは具体的なジェネリック型ではなく、ジェネリックの制約に従ってバインドされるため、この理解はジェネリックを扱う場合に特に重要です。たとえば、 methodSubDerivedClass:DerivedClassを作成したと、 new virtualmethodfoo()を定義したがあったとしDoFoo<T>(T param) where T:BaseClass {param.foo();}ます。メソッドが として呼び出された場合でも、呼び出しparam.foo()は にバインドされます。を呼び出す前にパラメーターが にキャストされた場合、呼び出しは にバインドされますが、コンパイラーは、それがより具体的なものになる時期を判断できず、 に存在しないものにはバインドできません。BaseClass.fooDoFoo<SubDrivedClass>(subDerivedInstance)SubDerivedClassfooSubDrivedClass.foo()DoFoo<T>TBaseClassBaseClass
ちなみに、クラスが基本クラスのメンバーを同時にオーバーライドし、新しいメンバーを作成できると便利な場合があります。たとえば、ReadableFoo読み取り専用の抽象プロパティを持つ抽象基本クラスがある場合、クラスMutableFooがそのプロパティのオーバーライドを提供し、同じ名前で読み書き可能なプロパティを定義できると便利です。残念ながら、.net ではそれが許可されていません。このような制限がある場合、別の名前のメソッドReadableFooを呼び出して値を取得する、具体的な非仮想の読み取り専用プロパティを提供するのが最善の方法かもしれません。protected abstractそうすれば、派生クラスは読み取り専用プロパティを読み取り/書き込みプロパティ (読み取り用に同じ仮想メソッドを呼び出すか、書き込み用に新しい (おそらく仮想) メソッドを呼び出す) でシャドウすることができます。
(以下は未確認)
class BaseClass
{
public virtual void foo() {Console.WriteLine("BaseClass.Foo");
}
class DerivedClass:BaseClass
{
public override void foo() {Console.WriteLine("Derived.Foo");
}
class SubDerivedClass:DerivedClass
{
public new virtual void foo() {Console.WriteLine("SubDerived.Foo");
}
class MegaDerivedClass:SubDerivedClass
{
public override void foo() {Console.WriteLine("MegaDerived.Foo");
}
void DoFoo1<T>(T param) where T:BaseClass
{
param.foo();
}
void DoFoo1<T>(T param) where T:SubDerivedClass
{
param.foo();
}
void test(void)
{
var megaDerivedInstance = new MegaDerivedClass();
DoFoo1<MegaDerivedClass>(megaDerivedInstance);
DoFoo2<MegaDerivedClass>(megaDerivedInstance);
}
SubDerivedClass には、 と の 2 つの仮想foo()メソッドがBaseClass.foo()ありSubDerivedClass.foo()ます。AMegaDerivedClassには同じ 2 つのメソッドがあります。SubDerivedClass()オーバーライドしようとする派生クラスfooはオーバーライドされSubDerivedClass.foo()、影響を与えないことに注意してくださいBaseClass.foo()。上記の宣言では、 の派生物はSubDerivedClassオーバーライドできませんBaseClass.Foo。SubDerivedClassまた、インスタンスまたはそのサブクラスをキャストするDerivedClassか、仮想メソッドを呼び出し用BaseClassに公開することにも注意してください。BaseClass.foo
ちなみに、 のメソッド宣言が でSubDerivedClassあった場合friend new virtual void foo() {Console.WriteLine("SubDerived.Foo");、同じアセンブリ内の他のクラスがオーバーライドすることはできませんBaseClass.foo()(オーバーライドしようとすると がオーバーライドさfoo()れるためSubDerivedClass.foo()) 。SubDerivedClassSubDerivedClass.foo()BaseClass.foo()