2

C# 経由で CLR から引用すると、CLR 経由callで実行時に基本型によって定義されたメソッドを検索するかのように読み取れます。

次に、callIL 命令を使用してインスタンスまたは仮想メソッドを呼び出します。オブジェクトを参照する変数を指定する必要があります。変数自体の型は、CLR が呼び出す必要があるメソッドを定義する型を示します。変数の型がメソッドを定義していない場合は、基本型が一致するメソッドについてチェックされます。

非仮想インスタンス メソッドを呼び出す場合、JIT は、呼び出しに使用されている変数の型に対応する型オブジェクトを見つけます。呼び出されるメソッドが型で定義されていない場合、JIT はクラス階層を下って Object に向かってこのメソッドを探します。これを行うことができるのは、各型オブジェクトにその基本型を参照するフィールドがあるためです。次に、JIT は、呼び出されているメソッドを参照する型オブジェクトのメソッド テーブル内のエントリを見つけます。

ただし、次の例に基づくと、メソッドの継承はコンパイル時にチェックされるようです。

class A
{
    public void Foo() {}
}
class B : A {}
void Main()
{
    new B().Foo();
}
IL_0000:  newobj      UserQuery+B..ctor
IL_0005:  call        UserQuery+A.Foo // Not B.Foo, resolved by C# complier.

私は正しいですか?

私がこれをしても:

void Main()
{
    B x = new B();
    x.Foo();
}
IL_0000:  newobj      UserQuery+B..ctor
IL_0005:  stloc.0     // x
IL_0006:  ldloc.0     // x
IL_0007:  callvirt    UserQuery+A.Foo // Not B.Foo, resolved by C# complier.

アップデート:

これで、解像度が静的であることがわかりました。

そして、JIT が必要とする変数の型は、実際にはメタデータ トークンによって指定されたクラスであると私は信じています。

重複アラート

実際には、非仮想メソッド呼び出しの内部を説明するときに Is Richter wrong? と重複しています。

私と同じ質問をした人がもう一人いてよかったです。

4

3 に答える 3

1

Richter は、ジッターの動作について説明しました。コンパイラには、それに依存する義務はありません。基本クラスのメソッドを確実に指定するのに十分な型情報が利用できる場合、C# コンパイラは確かにジッターの仕事を容易にするかもしれません。そして、そうします。

実際、C# コンパイラはbaseキーワードを実装するためにこれを行う必要があります。Foo() メソッドが仮想の場合、 base.Foo() 呼び出しは基本クラスを使用する必要があります。ジッターがこれを把握するための信頼できる方法はありません。使用できるのは、派生クラスのメソッド テーブルだけです。ただし、Foo() オーバーライドは、基本クラスの Foo() メソッドのメソッド アドレスを置き換えます。特にdynamicキーワードの問題です。

于 2013-07-23T12:09:28.473 に答える
0

実際、非仮想メソッドはコンパイル時に解決されます。これは、どのメソッドが呼び出されるかが確実であるためです。同じことが静的メソッドにも当てはまります。

逆に、仮想メソッドは実行時まで解決できません

于 2013-07-23T11:34:35.567 に答える