Подтвердить что ты не робот

Каков тип нулевого литерала?

D ухо все, интересно, какой тип null литерал в С#?

В Java литерал null имеет специальный нулевой тип:

Существует также специальный тип null, тип выражения null, который не имеет имени. Поскольку нулевой тип не имеет имени, невозможно объявить переменную нулевого типа или применить к нулевому типу. Нулевая ссылка - единственное возможное значение выражения нулевого типа. Нулевая ссылка всегда может быть применена к любому ссылочному типу.

В С++ 11 есть nullptr (рекомендуемая версия старого приятеля null), который имеет тип std::nullptr_t.

Я искал MSDN около С#, но спецификация, похоже, ничего не говорит об этом.

4b9b3361

Ответ 1

В соответствии с спецификацией языка ECMA С#:

9.4.4.6 Нулевой литерал:

Тип нуль-литерала - это нулевой тип (§11.2.7).

11.2.7 Нулевой тип:

Нулевой литерал (§9.4.4.6) оценивает нулевое значение, которое используется для обозначения ссылки, не указывающей на какой-либо объект или массив, или отсутствие значения. Тип null имеет одно значение, которое является нулевое значение. Следовательно, выражение, тип которого является нулевым, может оценивать только нулевое значение. Невозможно явно написать нулевой тип и, следовательно, никак не использовать его в объявленном типе. Более того, нулевой тип никогда не может быть типом, выведенным для типа параметр (§25.6.4)

Итак, чтобы ответить на ваш вопрос, null - это собственный тип - нулевой тип.

Хотя это странно, как он не упоминается в языковой спецификации С# 4.0 или языковой спецификации С# 3.0 но упоминается в обзоре С# 3.0, спецификации ECMA С# и Спецификация языка С# 2.0.

Ответ 2

UPDATE: Этот вопрос был предметом моего блога в июле 2013 года. Спасибо за отличный вопрос!


Ответ Дж.Коммера правильный (и хорош для них для того, чтобы делать то, что, очевидно, было много спекуляций!), но я думал, что добавлю немного исторической перспективы.

Когда мы с Мэдсом разобрали точную формулировку различных частей спецификации для С# 3.0, мы поняли, что "нулевой тип" был странным. Это "тип" с одним значением. Это "тип", о котором "Отражение" ничего не знает. Это "тип", который не имеет имени, которое GetType никогда не возвращает, что вы не можете указать в качестве типа локальной переменной или поля или чего-либо еще. Короче говоря, это действительно "тип", который должен только сделать систему типов "полной", так что каждое выражение времени компиляции имеет тип.

За исключением того, что у С# уже были выражения, у которых не было типов: группы методов в С# 1.0, анонимные методы в С# 2.0 и lambdas в С# 3.0 не имеют типа. Если все эти вещи не могут иметь никакого типа, мы поняли, что "нулевой" также не должен иметь тип. Поэтому мы удалили ссылки на бесполезный "нулевой тип" в С# 3.0.

В качестве детали реализации, реализации Microsoft с C 1.0 до 5.0 все имеют внутренний объект для представления "нулевого типа". У них также есть объекты для представления несуществующих типов лямбда, анонимных методов и групп методов. Этот выбор реализации имеет ряд плюсов и минусов. На стороне pro компилятор может запросить тип выражения и получить ответ. С другой стороны, это означает, что иногда ошибки в анализе типов, которые действительно должны были разбивать компилятор, вместо этого вызывают семантические изменения в программах. Моим любимым примером этого является то, что в С# 2.0 можно использовать недопустимое выражение "null? Null"; из-за ошибки компилятор не может отметить это как ошибочное использование оператора ??, и далее делает вывод о том, что тип этого выражения является "нулевым типом", хотя это не нулевой литерал. Затем это приводит к возникновению многих других ошибок в потоке, поскольку анализатор типов пытается понять тип.

В Roslyn мы, вероятно, не будем использовать эту стратегию; скорее, мы просто запекли в реализации компилятора, что некоторые выражения не имеют типа.

Ответ 3

Несмотря на отсутствие типа времени выполнения, 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; }