Правильно ли, что метод экземпляра может быть вызван по нулевой ссылке в IL ..? Есть ли пример, чтобы показать это ..?
Да, это возможно, если метод не использует this
, потому что CLR не выполняет нулевую проверку для инструкций call
.
Вам придется изменить IL вручную, поскольку компилятор 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 также есть хорошее объяснение в вопросе, относящемся к .
См. Информацию в моей записи в блоге .
Пример кода 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
}
}
CLR этого не требует, это деталь реализации языка. C # и VB.NET выполняют тест. C ++ / 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;
}