空文字的类型是什么?

本文关键字:是什么 类型 文字 | 更新日期: 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,但是您无法找到变量nullStringnullStringAsObject的任何类型。

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; }