是否null
有型?如何在内部表示空值?以下代码中发生了什么?
void Foo(string bar) {...} void Foo(object bar) {...} Foo((string)null);
编辑:迄今为止的答案都是非特定的,而且太高级了.我知道引用类型对象由堆栈上的指针组成,指针指向堆上的一个位置,该位置包含同步块索引,类型句柄和对象的字段.当我设置一个对象的实例时,null
堆栈上的指针指向哪里?而在代码片段,仅仅是使用C#编译器来决定哪些超载致电剧组,并没有真正空的事情进行任何造型?
我正在寻找了解CLR内部人员的深入答案.
演员到string
您的代码示例中没有给出null
一个类型,null
不能有类型本身.如果你想要证明这一点,那么执行下面的代码,你可以看到它null
总是等于它自己,不管它被赋给的变量类型是什么:
string s = null; IPAddress i = null; Console.WriteLine(object.Equals(s, i)); // prints "True" Console.WriteLine(object.ReferenceEquals(s, i)); // prints "True"
演员所做的是告诉编译器选择哪个重载.由于null
没有类型,它不知道是否选择带有object
a或a 的重载,string
因为该值可以被解释为.因此,您可以通过说"这是一个应该被视为字符串的空值"来帮助它.
如果你想看看下面发生了什么,那么从代码中查看IL.方法调用的相关位在文本IL中类似于以下内容(取决于您的命名空间和类名等):
ldnull call void ConsoleApplication1.Program::Foo(string)
所有发生的事情是在堆栈上加载null,然后由占用字符串的重载消耗,因为在编译时执行重载解析,因此调用的方法被烘焙到IL中.
如果你想看看是什么ldnull
,以及为什么它只是使用类似的东西ldc.i4.0
将零加载到堆栈上然后看到这个答案(如果你不想跟随链接,原因是它是一个与大小无关的零否则在CLR中不存在).
null没有类型,并且"在代码片段中,C#编译器只是使用它来决定调用哪个重载,并且实际上没有任何转换为null?" 正是这样.让我们看一下生成的IL.
IL_0001: ldnull IL_0002: call void ConsoleApplication1.Program::Foo(string)
注意ldnull将null加载到堆栈.它只是null,不是作为字符串或其他东西的null.重要的是第二行,其中IL显式调用接收字符串的重载.如果你打电话给对象,会发生以下情况:
IL_0001: ldnull IL_0002: call void ConsoleApplication1.Program::Foo(object)
所以,是的,强制转换是一个C#工件,因此编译器知道要调用的重载.