Вызов метода экземпляра по нулевой ссылке в IL - PullRequest
6 голосов
/ 10 августа 2010

Правильно ли, что метод экземпляра может быть вызван по пустой ссылке в IL .. Есть ли пример, чтобы показать это ..?

Ответы [ 3 ]

10 голосов
/ 10 августа 2010

Да, это возможно, если в методе не используется this, поскольку CLR не выполняет нулевую проверку для инструкций call.

Вам придется изменить IL с помощьюhand, поскольку компилятор C # почти всегда генерирует callvirt инструкцию 1 .

См. Этот пост в блоге для получения подробной информации и примера:

Методы экземпляра, вызываемые по пустым ссылкам

Образец

.method private hidebysig static void  Main(string[] args) cil managed
{
    .entrypoint
    // Code size       18 (0x12)
    .maxstack  1
    .locals init ([0] class SomeClass o, [1] string hello)
    IL_0000:  nop
    IL_0001:  ldnull
    IL_0002:  stloc.0
    IL_0003:  ldloc.0
    IL_0004:  call       instance string SomeClass::GetHello()
    IL_0009:  stloc.1
    IL_000a:  ldloc.1
    IL_000b:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0010:  nop
    IL_0011:  ret
} 

1 Фактически причина, по которой компилятор C # выдает callvirt, даже в тех случаях, когда простой инструкции call будет достаточночтобы предотвратить вызов методов экземпляра для нулевых ссылок.При таком поведении компилятора пользователи получат NullReferenceException, поэтому избегается странная ситуация вызова метода с нулевым указателем.Эрик Ганнерсон объяснил это в своем блоге некоторое время назад: Почему C # всегда использует callvirt? Gishu также имеет хорошее объяснение в связанный вопрос .

5 голосов
/ 10 августа 2010

См. Мою запись в блоге для информации.

Пример кода IL:

.class Program
{
  .method static void  Main(string[] args)
  {
    .entrypoint
    .locals init ([0] class Program p)
    ldloc.0 // but wait, it's still null!
    call   instance void Program::Awesome()
    ret
  } 

  .method instance void Awesome()
  {
    ldstr      "Awesome!"
    call       void [mscorlib]System.Console::WriteLine(string)
    ret
  } 

  .method public specialname rtspecialname instance void  .ctor()
  {
    ldarg.0
    call       instance void [mscorlib]System.Object::.ctor()
    ret
  }
}
3 голосов
/ 10 августа 2010

CLR не требует этого, это деталь реализации языка.C # и VB.NET выполняют тест.C ++ / CLI - известный управляемый язык, который позволяет это.Пока метод экземпляра не ссылается ни на один из членов класса, тогда все в порядке.Если это так, NullReferenceException будет вызываться в обычном режиме, и вам просто будет трудно понять, почему.

...