したがって、基本的に、呼び出されているメソッドが非仮想インスタンス メソッドか仮想メソッドかを判断するために C# コンパイラが実行する一般的な手順を理解したいと思います。
混乱は、これら 2 つの説明 (C# による CLR 第 3 版、Jeffrey Richter、Chapter 4 Type Fundamentals) から生じます。
非仮想インスタンス メソッドを呼び出す場合、JIT コンパイラは、呼び出しに使用されている変数の型に対応する型オブジェクトを見つけます。
仮想メソッド呼び出しの場合
仮想インスタンス メソッドを呼び出すと、JIT コンパイラはメソッド内に追加のコードを生成します。このコードは、メソッドが呼び出されるたびに実行されます。このコードは、最初に呼び出しを行うために使用されている変数を調べ、次に呼び出し元オブジェクトへのアドレスに従います。
小さなテストプロジェクトを作成しました
class Program
{
static void Main(string[] args)
{
Parent p = new Derived();
p.Foo(10); // Outputs Derived.Foo(int x)
Derived d = new Derived();
d.Foo(10); // Outputs Derived.Foo(double y)
}
}
internal class Parent
{
public virtual void Foo(int x)
{
Console.WriteLine("Parent.Foo(int x");
}
}
internal class Derived: Parent
{
public override void Foo(int x)
{
Console.WriteLine("Derived.Foo(int x)");
}
public void Foo(double y)
{
Console.WriteLine("Derived.Foo(double y)");
}
}
Jon Skeet は、なぜプログラムがこれらの出力を生成するのかを説明するブログ投稿を行っており、Eric Lippert は彼のブログ投稿(コメント セクションを確認してください) で、呼び出されているメソッドが非仮想であるかどうかをコンパイラがどのように判断するかをまだ理解できません。インスタンス メソッドまたは仮想メソッド。
非仮想インスタンスメソッド呼び出しの場合、コンパイラはメソッドの呼び出しに使用されている変数の型をチェックし、仮想メソッドの場合は、メソッドの呼び出しに使用されている変数によって参照されるオブジェクトの型をチェックしているようです。 、メソッドの実行方法を決定する前に、メソッドが非仮想か仮想かを判断する何らかの方法が必要です。