空文字的类型是什么?
本文关键字:是什么 类型 文字 | 更新日期: 2023-09-27 18:15:12
亲爱的,我想知道c#中null
文字的类型是什么?
在Java中,null
字面值是特殊的空类型:
还有一个特殊的空类型,即表达式
null
的类型,它没有名称。由于null类型没有名称,因此不可能声明null类型的变量或强制转换为null类型。null引用是null类型表达式的唯一可能值。空引用总是可以被强制转换为任何引用类型。
在c++ 11中,有nullptr
(老伙伴NULL
的推荐版本),类型为std::nullptr_t
。
我在MSDN上搜索了c#,但规范似乎没有说任何关于这方面的内容。
根据ECMA c#语言规范:
9.4.4.6空字面值:
null字面值的类型是null类型(第11.2.7节)。
11.2.7空类型:
null字面值(§9.4.4.6)计算为null值,它被使用表示不指向任何对象或数组的引用没有值。null类型只有一个值,即null值。因此,类型为空类型的表达式可以只计算为空值。没有办法显式地写null类型,因此无法在声明的类型中使用它。此外,null类型永远不能是为类型推断的类型参数(§25.6.4)
回答你的问题,null是它自己的类型,null类型。
虽然在c# 4.0语言规范和c# 3.0语言规范中没有提到它,但在c# 3.0、ECMA c#语言规范和c# 2.0语言规范的概述中都提到了它,这很奇怪。
更新:这个问题是我2013年7月博客的主题。谢谢你的好问题!
J。Kommer的回答是正确的(他们做了大量的spec挖掘,这对他们来说很好!),但我想我应该添加一点历史观点。
当Mads和我整理c# 3.0规范中各个部分的确切措辞时,我们意识到"null类型"很奇怪。它是一个只有一个值的"类型"。这是一种Reflection一无所知的"类型"。它是一个没有名字的类型,GetType永远不会返回,你不能指定为一个局部变量或字段或任何东西的类型。简而言之,它确实是一种"类型",它的存在只是为了使类型系统"完整",以便每个编译时表达式都有一个类型。
除了c#已经有了没有类型的表达式:c# 1.0中的方法组,c# 2.0中的匿名方法和c# 3.0中的lambda都没有类型。如果所有这些东西都没有类型,我们意识到"null"也不需要有类型。因此,我们在c# 3.0中删除了对无用的"null类型"的引用。
作为一个实现细节,c# 1.0到5.0的微软实现都有一个内部对象来表示"null类型"。它们也有对象来表示不存在的lambdas类型、匿名方法和方法组。这种实现选择有许多优点和缺点。优点是,编译器可以询问任何表达式的类型并获得答案。另一方面,这意味着有时类型分析中的错误本来应该导致编译器崩溃,但却导致了程序中的语义变化。我最喜欢的例子是,在c# 2.0中可以使用非法表达式"null ??"空";由于一个错误,编译器没有将其标记为??
操作符的错误使用,并继续推断该表达式的类型是"空类型",即使它不是空文字。当类型分析器试图理解类型时,这会导致许多其他的下游错误。
在Roslyn,我们可能不会使用这个策略;相反,我们将简单地在编译器实现中添加一些表达式没有类型。
尽管没有运行时类型,但null
可以在编译时强制转换为类型,如本例所示。
在运行时,您可以发现变量stringAsObject
包含string
,而不仅仅是object
,但是您无法找到变量nullString
和nullStringAsObject
的任何类型。
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; }