什么是空文字的types?

d 所有的耳朵,我不知道什么是在C#中的null字面的types?

在Java中, null文字是特殊的空types

还有一个特殊的空types ,expression式为null的types,它没有名字。 因为nulltypes没有名称,所以不可能声明nulltypes的variables或转换为nulltypes。 空引用是空typesexpression式的唯一可能值。 空引用总是可以转换为任何引用types。

在C ++ 11中,有nullptr (旧朋友的推荐版本为NULL ),它是std::nullptr_ttypes 。

我search了关于C#的MSDN,但是这个规范似乎没有提到什么。

根据ECMA C#语言规范 :

9.4.4.6 null文字:

空字面的types是空types(§11.2.7)。

11.2.7空types:

null文字(第9.4.4.6节)计算为空值,用于表示不指向任何对象或数组的引用,或缺less值。 空types有一个单值,即空值。 因此,types为空types的expression式只能计算为空值。 没有办法明确写入空types,因此,没有办法在声明的types中使用它。 而且,nulltypes永远不可能是types参数的types(§25.6.4)

所以要回答你的问题,null是它自己的types – nulltypes。

虽然在C#4.0语言规范或C#3.0语言规范中没有提到它,但在C#3.0 , ECMA C#语言规范和C#2.0语言规范的概述中提到了它。

更新: 这个问题是我的博客在2013年7月的主题。谢谢你的好问题!


J.Kommer的回答是正确的(对于做很多规范挖掘工作的人来说,他们的回答是正确的),但是我认为我会添加一些历史观点。

当Mads和我正在整理C#3.0规范的各个部分时,我们意识到“空types”是奇怪的。 这是一个只有一个值的“types”。 这是反思一无所知的“types”。 这是一个“types”,没有名称,GetType永不返回,你不能指定为本地variables或字段的types或任何东西。 简而言之,它只是使types系统“完整”的“types”,所以每个编译时expression式都有一个types。

除了C#已经有C#1.0中没有types:方法组的expression式之外,C#2.0中的匿名方法和C#3.0中的lambdaexpression式都没有types。 如果所有这些东西都没有types的话,我们意识到“null”也不一定有types。 因此,我们删除了对C#3.0中无用的“空types”的引用。

作为一个实现细节,C#1.0到5.0的Microsoft实现都有一个内部对象来表示“空types”。 他们也有对象来表示不存在的lambdaexpression式,匿名方法和方法组。 这个实施select有一些优点和缺点。 在专业方面,编译器可以询问任何expression式的types并获得答案。 另一方面,这意味着有时types分析中的错误应该使编译器崩溃,而不是导致程序中的语义变化。 我最喜欢的例子是,它可能在C#2.0中使用非法expression式“null ?? null”; 由于一个错误编译器无法将其标记为错误的使用?? 运算符,然后继续推断该expression式的types是“空types”,即使它不是空文字。 随着types分析器尝试理解types,会导致许多其他下游错误。

在Roslyn我们可能不会使用这个策略; 相反,我们只是简单地烘焙一下编译器的实现,即一些expression式没有types。

尽pipe没有运行时types,但可以在编译时将null转换为types,如本例所示。

在运行时,你可以发现variablesstringAsObject包含一个string ,不仅是一个object ,而且你也找不到variablesnullStringnullStringAsObject任何types。

 public enum Answer { Object, String, Int32, FileInfo }; private Answer GetAnswer(int i) { return Answer.Int32; } private Answer GetAnswer(string s) { return Answer.String; } private Answer GetAnswer(object o) { return Answer.Object; } [TestMethod] public void MusingAboutNullAtRuntimeVsCompileTime() { string nullString = null; object nullStringAsObject = (string)null; object stringAsObject = "a string"; // resolved at runtime Expect.Throws(typeof(ArgumentNullException), () => Type.GetTypeHandle(nullString)); Expect.Throws(typeof(ArgumentNullException), () => Type.GetTypeHandle(nullStringAsObject)); Assert.AreEqual(typeof(string), Type.GetTypeFromHandle(Type.GetTypeHandle(stringAsObject))); Assert.AreEqual(typeof(string), stringAsObject.GetType()); // resolved at compile time Assert.AreEqual(Answer.String, this.GetAnswer(nullString)); Assert.AreEqual(Answer.Object, this.GetAnswer(nullStringAsObject)); Assert.AreEqual(Answer.Object, this.GetAnswer(stringAsObject)); Assert.AreEqual(Answer.Object, this.GetAnswer((object)null)); Assert.AreEqual(Answer.String, this.GetAnswer((string)null)); Assert.AreEqual(Answer.String, this.GetAnswer(null)); } // Uncommenting the following method overload // makes the last statement in the test case ambiguous to the compiler // private Answer GetAnswer(FileInfo f) { return Answer.FileInfo; }