Ist es richtig, dass eine Instanzmethode für eine Nullreferenz in IL aufgerufen werden kann? Gibt es ein Beispiel, um dies zu zeigen ..?Aufruf der Instanzmethode für eine Nullreferenz in IL
Antwort
Ja, dies ist möglich, solange die Methode this
nicht verwendet, da die CLR keine call
Instruktionen überprüft.
Sie müssten die IL manuell ändern, da der C# -Compiler fast immer eine callvirt
Anweisung generieren würde.
dieses Blog-Post für Details und ein Beispiel:
Probe
.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
}
der Grund, dass der C# -Compiler In der Tat gibt 0 ausselbst in Fällen, in denen eine einfache Anweisung call
ausreichen würde, ist der Aufruf von Instanzmethoden für Nullverweise zu verhindern. Mit diesem Verhalten des Compilers erhalten Benutzer eine NullReferenceException
, so dass die seltsame Situation des Aufrufs einer Methode auf einen Nullzeiger vermieden wird. Eric Gunnerson erklärte das vor einiger Zeit in einem Blogpost: Why does C# always use callvirt?Gishu hat auch eine schöne Erklärung in einem related question.
Siehe meine blog entry für Info.
IL-Code Beispiel:
.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
}
}
Die CLR es nicht erforderlich ist, es ist eine Implementierung Detail der Sprache. C# und VB.NET führen den Test durch. C++/CLI ist eine bemerkenswerte verwaltete Sprache, die es erlaubt. Solange die Instanzmethode keine Klassenmitglieder referenziert, ist nichts falsch. Wenn dies der Fall ist, wird NullReferenceException wie normal ausgelöst, was es Ihnen nur schwer fällt herauszufinden, warum.
#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;
}
Sicher ist das nicht möglich - in welchem Fall würden Sie die Methode ausführen? –
@Adam: Es ist sehr möglich mit ein bisschen IL-Hackerei. Der Code ist immer noch zu 100% verifizierbar, aber der C# -Compiler würde niemals solchen Code ausgeben. – leppie
Fair genug, wie kommt es von der Null Referenz und Redirect auf die richtige Instanz im Speicher? Zum Beispiel, wenn die Methode den internen Status geändert hat. –