在工作中不小心写了下面这行代码:
string x = (object) null;
// It was var x = (object)null and I changed from var to string instead of
// object x = null;
这给了我一个类似于这样的编译错误:
Can't cast source type object to target type string
为什么?无论类型是什么,
null
不就是一堆指向“无处”内存地址的零吗?
问题不在于
null
的转换,而是object
不能分配给string
。 这个效果很好
string x = (string)null;
C# 语言规范第 2.4.4.6 节中列出了如果删除强制转换 (
string x = null
) 则此方法有效的原因
空文字可以隐式转换为引用类型或可空类型
引入强制转换 (
(object)null
) 的那一刻,您就不再拥有空文字。 相反,您有一个类型为 object
的值。 本质上与没有什么不同
object temp = null;
string x = temp;
这里的问题基本上是“为什么编译器不考虑它知道分配的值是已知为空的常量引用这一事实?”
答案是:为什么要这么做?考虑到这些信息有什么引人注目的好处?你故意说“我希望这个表达式被视为对象类型”,并且你不能将对象类型的值分配给字符串类型的变量。在这种情况下允许这样做有什么好处?
在我看来,该代码很可能是一个错误;当然编译器应该告诉你它而不是允许它。
无论类型是什么,null 不只是一堆指向“无处”内存地址的零吗?
这就是 C 或 C++ 等弱类型语言的全部内容。
在 C# 中,引用的类型是其标识的一个组成部分。
(string)null
与 (object)null
不同,因为一个是 string
,一个是 object
。
此外,在 C# 中
null
并没有真正对应的数字。 C# 中的引用与指针不同,从语义上讲,它们没有关联的内存地址。 null
只是意味着引用不指向对象,并且 null
引用的内部表示是实现细节。
它需要是可赋值的——即使它看起来是“相同的空值”并且没关系,编译器仍然支持该类型。其优点之一是解决过载问题:
void Foo(object bar) { ... }
void Foo(string bar) { ... }
Foo((object)null); // will call the former
Foo((string)null); // will call the latter
也许
object x = (string) null;
这可能有用,但你为什么要这么做呢?
因为对象可以容纳字符串,但是字符串不能容纳对象
字符串是从对象继承的,而不是相反。
您可以将 null 分配给任何引用类型的变量,而无需强制转换任何内容:
String x = null;
每个类都有一个定义列表:
Constructors
Destructors
Fields
Methods
Properties
Indexers
Delegates
Events
Nested Classes
Object 是一个泛型类型,因为每个类都继承自它,但反之则不然。每个类的这些定义都不相同,因此您的编译器可以决定可以相互分配/转换哪些类型。
然后你在做:
string x = (object)null;
编译器并不关心您首先尝试分配给 x 的值,但它会检查 string 的类型定义,只是不让您射击自己的腿,并生成错误,因为它是一种类型不匹配。