2010-08-10 5 views
6

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

+0

Sicher ist das nicht möglich - in welchem ​​Fall würden Sie die Methode ausführen? –

+2

@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

+0

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. –

Antwort

10

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:

Instance Methods Called on null References

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.

5

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 
    } 
} 
3

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; 
}