我假设您正在查看.NET 3.5的实现?我相信.NET 4的实现略有不同。
但是,我有一个偷偷摸摸的怀疑,这是因为甚至有可能 在null引用上
非虚拟地调用虚拟实例方法。即在IL中可能。我看看是否可以产生一些IL来调用
null.Equals(null)。
编辑:好的,这是一些有趣的代码:
.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我是通过编译以下C#代码得到的:
using System;class Test{ static void Main() { string x = null; Console.WriteLine(x.Equals(null)); }}…然后进行拆卸
ildasm和编辑。注意这一行:
IL_0005: call instance bool [mscorlib]System.String::Equals(string)
最初是
callvirt而不是
call。
那么,当我们重新组装时会发生什么呢?好了,有了.NET 4.0,我们得到了:
Unhandled Exception: System.NullReferenceException: Objectreference not set to an instance of an object. at Test.Main()
嗯 .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()
现在,这变得更有趣了……我们显然已经设法进入了
EqualsHelper,这是我们通常不会期望的。
足够的字符串…让我们尝试自己实现引用相等,看看是否可以
null.Equals(null)返回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; }}与以前相同的过程-拆卸,更改
callvirt为
call,重新组装并观看打印
true…
请注意,尽管另一个答案引用了这个C ++问题,但我们在这里更加曲解……因为我们非 虚拟地 调用 虚拟 方法。通常,即使C ++ /
CLI编译器也将
callvirt用于虚拟方法。换句话说,我认为在这种特殊情况下,唯一的为
thisnull的方法是手动编写IL。
编辑:我刚刚注意到了一些事情……我实际上并没有在我们的两个小示例程序中 都 调用正确的方法。这是第一种情况下的通话:
IL_0005: call instance bool [mscorlib]System.String::Equals(string)
这是第二个电话:
IL_0005: call instance bool [mscorlib]System.Object::Equals(object)
在第一种情况下,我 的意思 来调用
System.String::Equals(object),并在第二,我 的意思
打电话
Test::Equals(object)。从中我们可以看到三件事:
- 您需要小心过载。
- C#编译器向虚拟方法的 声明者 发出调用,而不是对虚拟方法的最具体的 覆盖 。IIRC,VB的工作方式相反
object.Equals(object)
很乐意比较一个空的“ this”引用
如果将控制台输出添加到C#覆盖中,您将看到区别-除非您更改IL以显式调用它,否则它将不会被调用,如下所示:
IL_0005: call instance bool Test::Equals(object)
所以,我们到了。空引用上实例方法的乐趣和滥用。
如果你走到今天这一步,你可能也想看看我的博客文章约值类型如何 可以
声明参数构造函数 …在IL。



