null有一个类型?如何在内部表示一个空值?以下代码发生了什么?
void Foo(string bar) {...} void Foo(object bar) {...} Foo((string)null);
编辑:迄今为止的答案是非特定的和太高的级别.引用类型对象由一个指向堆栈的指针组成,它指向堆上的一个位置,它包含同步块索引,类型句柄和对象的字段.当我将一个对象的实例设置为null时,堆栈上的指针指向哪里?而在代码片段中,C#编译器简单地使用的转换来决定要调用哪个重载,并且没有真正的任何转换为null?
我正在寻找一个了解CLR内部人员的深入回答.
解决方法
代码示例中的转换字符串不会给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没有类型,因此不知道是否选择接受对象或字符串的重载,因为值可以被解释为.所以你正在帮助它说“这是一个空值,应该被视为一个字符串”.
如果你想看看下面发生了什么,那么看看你的代码中的IL.方法调用的相关位在文本IL中类似于以下内容(取决于您的命名空间和类名等):
ldnull call void ConsoleApplication1.Program::Foo(string)
所以发生这种情况的是,在堆栈中加载一个空值,然后由占用字符串的重载消耗,因为在编译时执行重载分辨率,所以调用方法被烧录到IL中.
如果你想看看ldnull的作用,以及为什么不像使用像ldc.i4.0这样的东西把零加载到堆栈上,那么看到this answer(如果你不想跟随链接,原因是它是否则不存在于CLR中的大小不相关的零).