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


Dухо все, интересно, что это за тип null литерала в C#?

в Java null литерал особый тип null:

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

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

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

3   51   2011-11-21 00:44:05

3 ответа:

по словам спецификация языка ECMA C#:

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

тип нулевого литерала является нулевым типом (§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 года. Спасибо за отличный вопрос!


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

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

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

как деталь реализации, реализации Microsoft C# 1.0 - 5.0 все имеют внутренний объект для представления "нулевого типа". Они также имеют объекты для представления несуществующих типов лямбд, анонимных методов и групп методов. Этот выбор реализации имеет ряд плюсов и аферы. На стороне pro компилятор может запросить тип любого выражения и получить ответ. С другой стороны, это означает, что иногда ошибки в анализе типов, которые действительно должны были разбить компилятор, вместо этого вызывают семантические изменения в программах. Мой любимый пример этого заключается в том, что в C# 2.0 можно использовать незаконное выражение "null ?? 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; }