Верно ли, что метод экземпляра может быть вызван для нулевой ссылки в IL ..? Есть ли какой-нибудь пример, чтобы показать это ..?
Вызов метода экземпляра для нулевой ссылки в IL
Ответы (3)
Да, это возможно, если метод не использует 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;
}