Je suppose que vous cherchez à la .NET 3.5 mise en œuvre? Je crois que l' .NET 4 mise en œuvre est légèrement différente.
Cependant, j'ai l'intuition que c'est parce qu'il est possible de faire appel, même virtuel méthodes d'instance non-pratiquement sur une référence null. Possible dans l'ILLINOIS, qui est. Je vais voir si je peux produire de l'IL qui appellent null.Equals(null)
.
EDIT: Bon, voici quelques codes intéressants:
.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
Je l'ai obtenu par la compilation du code C# suivant:
using System;
class Test
{
static void Main()
{
string x = null;
Console.WriteLine(x.Equals(null));
}
}
... et puis à démonter avec ildasm
et l'édition. Remarque cette ligne:
IL_0005: call instance bool [mscorlib]System.String::Equals(string)
À l'origine, qui a été callvirt
au lieu de call
.
Donc, ce qui arrive quand nous le remonter? Eh bien, avec .NET 4.0 nous obtenons ceci:
Unhandled Exception: System.NullReferenceException: Object
reference not set to an instance of an object.
at Test.Main()
Hmm. Ce sur avec .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()
Maintenant, c'est plus intéressant... nous avons clairement réussi à obtenir en EqualsHelper
, ce qui nous n'aurions pas normalement.
Assez de ficelle... nous allons essayer de mettre en œuvre la référence à l'égalité de nous-mêmes, et de voir si nous pouvons obtenir de l' null.Equals(null)
retourner la valeur true:
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;
}
}
Même procédure qu'avant de démonter, modifier callvirt
de call
, remonter, et de le regarder à imprimer true
...
Notez que bien que l'autre répond références de ce C++ question, nous sommes d'être encore plus sournois ici... parce que nous allons appeler un virtuel méthode non-virtuelle. Normalement, même le C++/CLI compilateur utilisera callvirt
pour une méthode virtuelle. En d'autres termes, je pense que dans ce cas particulier, la seule façon pour this
à la valeur null est d'écrire le IL par la main.
EDIT: je viens de remarquer quelque chose... je n'ai pas fait appel de la méthode en soit de notre petit échantillon de programmes. Voici l'appel dans le premier cas:
IL_0005: call instance bool [mscorlib]System.String::Equals(string)
voici l'appel de la deuxième:
IL_0005: call instance bool [mscorlib]System.Object::Equals(object)
Dans le premier cas, j'ai signifié à l'appel System.String::Equals(object)
, et dans le deuxième, j'ai signifié à l'appel Test::Equals(object)
. De cela, nous pouvons voir trois choses:
- Vous devez être prudent avec la surcharge.
- Le compilateur C# émet des appels pour le preneur de la méthode virtuelle - pas le plus spécifique de la remplacer de la méthode virtuelle. IIRC, VB fonctionne à l'inverse
-
object.Equals(object)
est heureux de comparer un nul "ce" de référence
Si vous ajoutez un peu de console de sortie pour le C# remplacer, vous pouvez voir la différence, il ne sera pas appelé, sauf si vous modifiez le IL à l'appeler explicitement, comme ceci:
IL_0005: call instance bool Test::Equals(object)
Donc, nous y sommes. Le plaisir et l'abus de méthodes d'instance sur des références nulles.
Si vous avez rendu à ce point, vous pouvez aussi regarder mon blog à propos de la façon dont les types de valeur peut déclarer sans paramètre constructeurs... dans IL.