Dear all, I wonder what is the type of null
literal in C#?
亲爱的大家,我想知道c#中的空文字类型是什么?
In Java, the null
literal is of the special null type:
在Java中,null文字属于特殊的null类型:
There is also a special null type, the type of the expression
null
, which has no name. Because the null type has no name, it is impossible to declare a variable of the null type or to cast to the null type. The null reference is the only possible value of an expression of null type. The null reference can always be cast to any reference type.还有一个特殊的空类型,表达式null的类型,它没有名称。因为空类型没有名称,所以不可能声明空类型的变量或强制转换为空类型。空引用是空类型表达式的唯一可能值。空引用总是可以被转换为任何引用类型。
In C++11, there is nullptr
(the recommended version of the old buddy NULL
), which is of type std::nullptr_t
.
在c++ 11中,有nullptr(旧的buddy NULL的推荐版本),它是std::nullptr_t。
I searched MSDN about C#, but the specification doesn't seem to say anything about that.
我搜索了MSDN关于c#的内容,但是规范似乎并没有说明什么。
3 个解决方案
#1
53
According to the ECMA C# language specification:
根据ECMA c#语言规范:
9.4.4.6 The null literal:
9.4.4.6零文字:
The type of a null-literal is the null type (§11.2.7).
null字母是零类型的类型(§11.2.7)。
11.2.7 The null type:
11.2.7零类型:
The null literal (§9.4.4.6) evaluates to the null value, which is used to denote a reference not pointing at any object or array, or the absence of a value. The null type has a single value, which is the null value. Hence an expression whose type is the null type can evaluate only to the null value. There is no way to explicitly write the null type and, therefore, no way to use it in a declared type. Moreover, the null type can never be the type inferred for a type parameter (§25.6.4)
零文字(§9.4.4.6)等于零值,用来表示不指向任何对象或数组的引用,或者没有价值的。空类型只有一个值,即空值。因此,类型为空类型的表达式只能计算空值。没有办法显式地写入空类型,因此也没有办法在声明的类型中使用它。此外,空类型不能是类型参数的类型推断(§25.6.4)
So to answer your question, null is it's own type - the null type.
为了回答你的问题,null是它自己的类型,null类型。
Although it's odd how it's not mentioned in the C# 4.0 language specification or the C# 3.0 language specification but is mentioned in the overview of C# 3.0, the ECMA C# language specification and the C# 2.0 language specification.
虽然奇怪的是,c# 4.0语言规范或c# 3.0语言规范中没有提到它,但是在c# 3.0、ECMA c#语言规范和c# 2.0语言规范的概述中提到了它。
#2
43
UPDATE: This question was the subject of my blog in July 2013. Thanks for the great question!
更新:这个问题是我2013年7月博客的主题。谢谢你的问题!
J.Kommer's answer is correct (and good on them for doing what was evidently a lot of spec digging!) but I thought I'd add a little historical perspective.
J。Kommer的答案是正确的(这对他们来说很好,因为他们显然做了大量的规范挖掘!)
When Mads and I were sorting out the exact wording of various parts of the specification for C# 3.0 we realized that the "null type" was bizarre. It is a "type" with only one value. It is a "type" that Reflection knows nothing about. It is a "type" that doesn't have a name, that GetType never returns, that you can't specify as the type of a local variable or field or anything. In short, it really is a "type" that is there only to make the type system "complete", so that every compile-time expression has a type.
当Mads和我整理c# 3.0规范中各个部分的确切措辞时,我们意识到“空类型”很奇怪。它是一个只有一个值的“类型”。这是一种反射不知道的“类型”。它是一种没有名称的“类型”,GetType永远不会返回,您不能将其指定为局部变量或字段或其他类型。简而言之,它确实是一种“类型”,它只会使类型系统“完成”,以便每个编译时表达式都有一个类型。
Except that C# already had expressions that had no type: method groups in C# 1.0, anonymous methods in C# 2.0 and lambdas in C# 3.0 all have no type. If all those things can have no type, we realized that "null" need not have a type either. Therefore we removed references to the useless "null type" in C# 3.0.
除了c#已经有没有类型的表达式:c# 1.0中的方法组、c# 2.0中的匿名方法和c# 3.0中的lambdas都没有类型。如果所有这些东西都没有类型,我们意识到“null”也不需要类型。因此,我们删除了对c# 3.0中无用的“空类型”的引用。
As an implementation detail, the Microsoft implementations of C# 1.0 through 5.0 all do have an internal object to represent the "null type". They also have objects to represent the non-existing types of lambdas, anonymous methods and method groups. This implementation choice has a number of pros and cons. On the pro side, the compiler can ask for the type of any expression and get an answer. On the con side, it means that sometimes bugs in the type analysis that really ought to have crashed the compiler instead cause semantic changes in programs. My favourite example of that is that it is possible in C# 2.0 to use the illegal expression "null ?? null"; due to a bug the compiler fails to flag it as an erroneous usage of the ??
operator, and goes on to infer that the type of this expression is "the null type", even though that is not a null literal. That then goes on to cause many other downstream bugs as the type analyzer tries to make sense of the type.
作为实现细节,c# 1.0到5.0的Microsoft实现都有一个内部对象来表示“null类型”。它们还具有对象来表示不存在的lambdas类型、匿名方法和方法组。这个实现选择有许多优点和缺点。在正面,编译器可以询问任何表达式的类型并得到答案。另一方面,它意味着有时候类型分析中的错误(应该使编译器崩溃)反而会导致程序中的语义变化。我最喜欢的例子是c# 2.0中可以使用非法表达式“null ??”空”;由于错误,编译器不能将其标记为错误使用?运算符,并继续推断这个表达式的类型是“空类型”,即使它不是空文字。然后,当类型分析器试图理解类型时,这会导致许多其他的下游bug。
In Roslyn we will probably not use this strategy; rather, we'll simply bake into the compiler implementation that some expressions have no type.
在罗斯林,我们可能不会使用这种策略;相反,我们只需要将一些表达式的类型转换为编译器实现。
#3
0
Despite of having no runtime type, null
can be cast to a type at compile time, as this example shows.
尽管没有运行时类型,但可以在编译时将null转换为类型,如本例所示。
At runtime, you can find that variable stringAsObject
holds a string
, not only an object
, but you cannot find any type for variables nullString
and nullStringAsObject
.
在运行时,您可以发现变量stringAsObject持有一个字符串,不仅是一个对象,而且还不能为变量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; }
#1
53
According to the ECMA C# language specification:
根据ECMA c#语言规范:
9.4.4.6 The null literal:
9.4.4.6零文字:
The type of a null-literal is the null type (§11.2.7).
null字母是零类型的类型(§11.2.7)。
11.2.7 The null type:
11.2.7零类型:
The null literal (§9.4.4.6) evaluates to the null value, which is used to denote a reference not pointing at any object or array, or the absence of a value. The null type has a single value, which is the null value. Hence an expression whose type is the null type can evaluate only to the null value. There is no way to explicitly write the null type and, therefore, no way to use it in a declared type. Moreover, the null type can never be the type inferred for a type parameter (§25.6.4)
零文字(§9.4.4.6)等于零值,用来表示不指向任何对象或数组的引用,或者没有价值的。空类型只有一个值,即空值。因此,类型为空类型的表达式只能计算空值。没有办法显式地写入空类型,因此也没有办法在声明的类型中使用它。此外,空类型不能是类型参数的类型推断(§25.6.4)
So to answer your question, null is it's own type - the null type.
为了回答你的问题,null是它自己的类型,null类型。
Although it's odd how it's not mentioned in the C# 4.0 language specification or the C# 3.0 language specification but is mentioned in the overview of C# 3.0, the ECMA C# language specification and the C# 2.0 language specification.
虽然奇怪的是,c# 4.0语言规范或c# 3.0语言规范中没有提到它,但是在c# 3.0、ECMA c#语言规范和c# 2.0语言规范的概述中提到了它。
#2
43
UPDATE: This question was the subject of my blog in July 2013. Thanks for the great question!
更新:这个问题是我2013年7月博客的主题。谢谢你的问题!
J.Kommer's answer is correct (and good on them for doing what was evidently a lot of spec digging!) but I thought I'd add a little historical perspective.
J。Kommer的答案是正确的(这对他们来说很好,因为他们显然做了大量的规范挖掘!)
When Mads and I were sorting out the exact wording of various parts of the specification for C# 3.0 we realized that the "null type" was bizarre. It is a "type" with only one value. It is a "type" that Reflection knows nothing about. It is a "type" that doesn't have a name, that GetType never returns, that you can't specify as the type of a local variable or field or anything. In short, it really is a "type" that is there only to make the type system "complete", so that every compile-time expression has a type.
当Mads和我整理c# 3.0规范中各个部分的确切措辞时,我们意识到“空类型”很奇怪。它是一个只有一个值的“类型”。这是一种反射不知道的“类型”。它是一种没有名称的“类型”,GetType永远不会返回,您不能将其指定为局部变量或字段或其他类型。简而言之,它确实是一种“类型”,它只会使类型系统“完成”,以便每个编译时表达式都有一个类型。
Except that C# already had expressions that had no type: method groups in C# 1.0, anonymous methods in C# 2.0 and lambdas in C# 3.0 all have no type. If all those things can have no type, we realized that "null" need not have a type either. Therefore we removed references to the useless "null type" in C# 3.0.
除了c#已经有没有类型的表达式:c# 1.0中的方法组、c# 2.0中的匿名方法和c# 3.0中的lambdas都没有类型。如果所有这些东西都没有类型,我们意识到“null”也不需要类型。因此,我们删除了对c# 3.0中无用的“空类型”的引用。
As an implementation detail, the Microsoft implementations of C# 1.0 through 5.0 all do have an internal object to represent the "null type". They also have objects to represent the non-existing types of lambdas, anonymous methods and method groups. This implementation choice has a number of pros and cons. On the pro side, the compiler can ask for the type of any expression and get an answer. On the con side, it means that sometimes bugs in the type analysis that really ought to have crashed the compiler instead cause semantic changes in programs. My favourite example of that is that it is possible in C# 2.0 to use the illegal expression "null ?? null"; due to a bug the compiler fails to flag it as an erroneous usage of the ??
operator, and goes on to infer that the type of this expression is "the null type", even though that is not a null literal. That then goes on to cause many other downstream bugs as the type analyzer tries to make sense of the type.
作为实现细节,c# 1.0到5.0的Microsoft实现都有一个内部对象来表示“null类型”。它们还具有对象来表示不存在的lambdas类型、匿名方法和方法组。这个实现选择有许多优点和缺点。在正面,编译器可以询问任何表达式的类型并得到答案。另一方面,它意味着有时候类型分析中的错误(应该使编译器崩溃)反而会导致程序中的语义变化。我最喜欢的例子是c# 2.0中可以使用非法表达式“null ??”空”;由于错误,编译器不能将其标记为错误使用?运算符,并继续推断这个表达式的类型是“空类型”,即使它不是空文字。然后,当类型分析器试图理解类型时,这会导致许多其他的下游bug。
In Roslyn we will probably not use this strategy; rather, we'll simply bake into the compiler implementation that some expressions have no type.
在罗斯林,我们可能不会使用这种策略;相反,我们只需要将一些表达式的类型转换为编译器实现。
#3
0
Despite of having no runtime type, null
can be cast to a type at compile time, as this example shows.
尽管没有运行时类型,但可以在编译时将null转换为类型,如本例所示。
At runtime, you can find that variable stringAsObject
holds a string
, not only an object
, but you cannot find any type for variables nullString
and nullStringAsObject
.
在运行时,您可以发现变量stringAsObject持有一个字符串,不仅是一个对象,而且还不能为变量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; }