Ich nehme an, Sie haben sich die .NET 3.5-Implementierung angesehen? Ich glaube, dass die Implementierung von .NET 4 etwas anders ist.
Ich habe jedoch einen schleichenden Verdacht, dass dies daran liegt, dass es möglich ist, auch virtuelle Instanz Methoden nicht virtuell auf eine Null-Referenz aufrufen. Möglich in IL, das ist. Ich werde sehen, ob ich etwas IL produzieren kann, das null.Equals(null)
rufen würde.
EDIT: Okay, hier einige interessante Code:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 17 (0x11)
.maxstack 2
.locals init (string V_0)
IL_0000: nop
IL_0001: ldnull
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldnull
IL_0005: call instance bool [mscorlib]System.String::Equals(string)
IL_000a: call void [mscorlib]System.Console::WriteLine(bool)
IL_000f: nop
IL_0010: ret
} // end of method Test::Main
ich diese bekam durch den folgenden C# -Code kompilieren:
using System;
class Test
{
static void Main()
{
string x = null;
Console.WriteLine(x.Equals(null));
}
}
... und dann mit ildasm
und Bearbeitung zu zerlegen. Beachten Sie die folgende Zeile:
IL_0005: call instance bool [mscorlib]System.String::Equals(string)
Ursprünglich war das callvirt
statt call
.
Also, was passiert, wenn wir es wieder zusammensetzen? Nun, mit .NET 4.0 bekommen wir das:
Unhandled Exception: System.NullReferenceException: Object
reference not set to an instance of an object.
at Test.Main()
Hmm. Was ist mit .NET 2.0?
Unhandled Exception: System.NullReferenceException: Object reference
not set to an instance of an object.
at System.String.EqualsHelper(String strA, String strB)
at Test.Main()
Nun, das ist interessanter ... wir haben deutlich bekommen in EqualsHelper
verwaltet, was würden wir normalerweise nicht zu erwarten.
Genug der Zeichenfolge ... wollen wir versuchen Referenz Gleichheit selbst zu implementieren und sehen, ob wir null.Equals(null)
true zurück bekommen kann:
using System;
class Test
{
static void Main()
{
Test x = null;
Console.WriteLine(x.Equals(null));
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public override bool Equals(object other)
{
return other == this;
}
}
Die gleiche Prozedur wie vor - zerlegen, callvirt
-call
ändern, wieder zusammenzusetzen, und beobachten sie es true
drucken ...
Beachten sie, dass, obwohl eine andere Antworten verweist this C++ question, wir sind noch hier verschlagen ... weil wir den Aufruf einer virtuellen Methode nicht -virtuell. Normalerweise verwendet sogar der C++/CLI-Compiler callvirt
für eine virtuelle Methode. Mit anderen Worten, ich denke, in diesem speziellen Fall ist der einzige Weg für this
Null zu sein, die IL von Hand zu schreiben.
EDIT: Ich habe gerade etwas bemerkt ... ich eigentlich nicht in entweder unserer kleinen Beispielprogramme die richtige Methode aufrufen. Hier ist der Aufruf im ersten Fall:
IL_0005: call instance bool [mscorlib]System.String::Equals(string)
hier ist der Aufruf in den zweiten:
IL_0005: call instance bool [mscorlib]System.Object::Equals(object)
Im ersten Fall, ich bedeuten System.String::Equals(object)
zu nennen, und in den zweiten, ich gemeint anrufen Test::Equals(object)
. Von diesem können wir drei Dinge sehen:
- Sie müssen vorsichtig mit Überladung sein.
- Der C# -Compiler sendet Aufrufe an den -Deklarator der virtuellen Methode - nicht die spezifischste überschreiben der virtuellen Methode. IIRC, VB arbeitet die entgegengesetzte Richtung
object.Equals(object)
ist glücklich, eine Null „diese“ Referenz
zu vergleichen Wenn Sie ein bisschen von Konsolenausgabe zur Überschreibung C# hinzufügen, können Sie den Unterschied sehen können - es wird nicht aufgerufen werden, es sei denn, Sie ändern die AWL so, dass sie explizit aufgerufen wird:
Also, da sind wir. Spaß und Missbrauch von Instanzmethoden auf Null-Referenzen.
Wenn Sie es bis hierher geschafft haben, können Sie auch meinen Blogpost über how value types can declare parameterless constructors ... in IL ansehen.
Können Sie auch einen Blick auf EqualsHelper nehmen? Es scheint, dass sie EqualsHelper verwenden wollten, aber sie können die Nullwerte nicht so behandeln, wie sie es wollten. –
Dies ist besonders interessant, da die Dokumentation explizit besagt, dass Equals eine NullReferenceException auslöst, wenn die Instanz null ist. – womp
Meine Vermutung ist, dass es entweder ein Versehen ist oder etwas damit zu tun hat, wie 'EqualsHelper' funktioniert. Ich kann nicht wirklich eine Notwendigkeit für diese 'if' Aussage sehen, vorausgesetzt,' EqualsHelper' würde 'false' zurückgeben, wenn' strB' 'null' ist und' this' nicht. Aber vielleicht bin ich einfach nicht intelligent genug, um zu verstehen :) –