Как base.ToString (), вызываемая с помощью callvirt, может привести к исключению StackOverflow? - PullRequest
5 голосов
/ 09 февраля 2010

IL предлагает два оператора для вызова функций, т.е. call и callvirt. Вызов используется для вызова не виртуальных или статических функций или любой функции, в которой компилятор не хочет выполнять нулевую проверку ссылки.

callvirt используется для вызова виртуальных функций, также вызываются не виртуальные функции, так как компилятор выполняет нулевую проверку ссылки во время выполнения.

Теперь, проходя через CLR через C #, я нашел следующий пример.

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

Теперь ToString () является виртуальной функцией, но компилятор генерирует для нее инструкцию вызова, и это нормально. Но причина, по которой Джеффри упомянул, почему callvirt не генерируется, потому что в этом случае ToString () будет вызываться рекурсивно и вызовет StackOverFlow Exception, я пытался понять, но не смог обдумать эту идею? Может кто-нибудь объяснить, почему это вызовет рекурсивный вызов?

спасибо ..

Ответы [ 2 ]

2 голосов
/ 09 февраля 2010

Явный вызов определенного суперкласса (в данном случае System.Object, потому что вы написали base) должен не быть callvirt, поскольку это может привести к переполнению стека.

Некоторые псевдокод 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()
   }
}

Надеюсь, это то, что вы имели в виду.

2 голосов
/ 09 февраля 2010

из того, что я считаю, исключение stackoverflow произойдет, если компилятор сгенерирует callvirt, потому что:

Некоторые коды вызывают ToString объекта типа someclass , который наследуется от класса object . Метод ToString of * somclass "вызывает метод ToString своего базового класса, который является object .

Если этот вызов будет виртуальным, это приведет не к вызову ToString из класса object , а к вызову ToString класса actall (который равен SomeClass ).

Тогда вы будете в бесконечном цикле, поскольку все это начнется с нового сейчас.

...