Вызов метода экземпляра на нулевой ссылке в IL

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

3 ответа

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

Вам нужно будет вручную модифицировать IL, поскольку компилятор С# почти всегда генерирует команду 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 Фактически причина, по которой компилятор С# испускает callvirt даже в тех случаях, когда достаточно простой инструкции call, является предотвращение вызова методов экземпляра на нулевые ссылки. При таком поведении компилятора пользователи получат NullReferenceException, поэтому избегают странной ситуации вызова метода на нулевом указателе. Эрик Ганнерсон объяснил это в блоге некоторое время назад: Почему С# всегда использует callvirt?Gishu также имеет приятное объяснение в связанном вопросе.


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

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

.class Program
{
 .method static void Main(string[] args)
 {
 .entrypoint
 .locals init ([0] class Program p)
 ldloc.0 // but wait, it 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
 }
}


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

#include "stdafx.h"
using namespace System;
ref class Test {
public:
 void Run() {
 Console::WriteLine("no problem");
 }
};
int main(array<system::string ^=""> ^args)
{
 Test^ obj = nullptr;
 obj->Run();
 return 0;
}
</system::string>

licensed under cc by-sa 3.0 with attribution.