[英]In .Net/C#, is null strongly-typed?
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
或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#工件,因此编译器知道要调用的重载。
它将调用Foo(字符串栏)。
你可以抛空null。
null关键字是表示空引用的文字,不引用任何对象。 null是引用类型变量的默认值。 来自MSDN 。 所以你的例子中String的默认值。
// A null string is not the same as an empty string.
string s = null;
string t = String.Empty; // Logically the same as ""
你正在做的相当于按照上面的使用默认值:
int equal = string.Compare((string)null, default(string));
NULL是标记,它没有数据类型。当您将.NULL分配给字段或变量时,该值将更改为NULL,但字段或变量的数据类型不会更改。
在我的示例中将字符串类型指定为null的原因我认为是为了显示将使用witch方法(在这种情况下为“void Foo(string bar){...}”,因为这是接受字符串作为参数的方法。)
如果你会调用Foo((object)null); 将使用另一种方法。(“void Foo(object bar){...}”)
ECMA-334定义了null
值的类型,如下所示:
11.2.7 null类型
null literal(§9.4.4.6)求值为null值,该值用于表示不指向任何对象或数组的引用,或者缺少值。 null类型具有单个值,即null值。 因此,类型为null类型的表达式只能计算null值。 无法显式写入null类型,因此无法在声明的类型中使用它。
null类型是类型层次结构的底部类型 - 与object相反; null类型可以被认为是每个可空类型的子类型,因为null值可以在任何可以为空的表达式出现的地方使用。
这确实在类型系统中创建了一个弱点,因为它意味着其接收器是可空类型的任何操作都可以为null,并且操作可能在运行时因异常而失败。 在强类型系统中,如果接收器属于该类型,则保证由类型提供的操作(即,您不会获得空指针异常,这实际上是说null类型没有实现您所使用的任何方法在它上面调用,虽然null值可以来自你认为你正在使用的任何类型的表达式)。
在您的代码中,方法被重载,并且产生参数的表达式的静态类型用于重载解析。 由于强制转换为字符串,表达式具有类型字符串(null类型是字符串的子类型,根据C#类型系统,这是一个上传,所以是安全的)。 作为第一个近似值,编译器选择最具体的重载可见,因此选择Foo
的字符串版本而不是对象版本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.