5

IL は、関数を呼び出すための 2 つのステートメント、つまり call と callvirt を提供します。Call は、非仮想関数または静的関数、またはコンパイラが参照に対して null チェックを実行したくない関数を呼び出すために使用されます。

callvirt は仮想関数を呼び出すために使用されます。コンパイラは実行時に参照に対して null チェックを行うため、非仮想関数も呼び出されます。

C#経由でCLRを調べているときに、次の例が見つかりました。

internal class SomeClass
{
   public override String ToString()
   {
      return base.ToString();
   }
}

現在、ToString() は仮想関数ですが、コンパイラはそれに対する呼び出し命令を生成しますが、Jeffrey が callvirt が生成されない理由について言及した理由は、その場合、ToString() が再帰的に呼び出され、StackOverFlow 例外が発生するためです。私は理解しようとしましたが、この考えを理解することができませんでした? 再帰呼び出しが発生する理由を誰か説明できますか?

ありがとう..

4

2 に答える 2

2

私が信じていることから、コンパイラが callvirt を生成した場合、次の理由でスタックオーバーフロー例外が発生します。

一部のコードは、クラスobjectから継承するsomeclass型のオブジェクトの ToString を呼び出します。*somclass" メソッドの ToString は、 objectであるその基本クラスの ToString メソッドを呼び出します。

この呼び出し仮想の場合、クラスオブジェクトからの ToString の呼び出しではなく、実際のクラス ( SomeClass ) の ToString の呼び出しになります。

そうすれば、すべてが新しい今から始まるので、無限ループに陥るはずです。

于 2010-02-09T08:16:08.073 に答える
2

特定のスーパー クラスへの明示的な呼び出し (この場合System.Objectは.basecallvirt

いくつかの C# 疑似コード:

internal class SomeClass
{
   public override String ToString()
   {
       // The "return base.ToString()" call could produce one of these two possibilities:

       // This will NOT go through the class hierarchy, searching for a overwritten function
       // called ToString
       call and return System.Object::ToString()

       // But this WILL, thus calling SomeClass::ToString() recursively, so this is wrong
       // and would lead to a stack overflow
       callvirt and return System.Object::ToString()
   }
}

それがあなたの意図したことであることを願っています。

于 2010-02-09T08:19:23.260 に答える