Почему я не могу использовать инициализатор массива с неявно типизированной переменной?

Почему я не могу использовать инициализатор массива с неявно типизированной переменной?

string[] words = { "apple", "strawberry", "grape" };                 // legal
string[] words = new string[]{ "apple", "strawberry", "grape" };     // legal
var words = new []{ "apple", "strawberry", "grape" };                // legal
var words = new string[]{ "apple", "strawberry", "grape" };          // legal

var words = { "apple", "strawberry", "grape", "peach" };             // ILLEGAL

Есть ли техническая причина для этого ограничения? Почему он не может вывести такой тип, как он:

var number = 10;
var text = "Hello";

Компилятор четко знает, что я пытаюсь сделать, он просто не позволит:

CS0820: Невозможно назначить инициализатор массива неявно типизированным локальным


Обновление: я скомпилировал программу, используя четыре метода объявления законного массива, и генерирует тот же IL: http://pastebin.com/28JDAFbL

Это просто добавляет к моей путанице. И "это так, потому что спецификация говорит так", мало помогает. Почему спецификация такая? В чем здесь причина?

Ответы

Ответ 1

Почему я не могу использовать инициализатор массива с неявно типизированной переменной? Почему спецификация такая? В чем здесь причина?

Я не был в команде дизайнеров, когда это решение было принято, и примечания к дизайну (*) не читают эту тему. Тем не менее, я спросил кого-то, кто был в комнате в 2005 году, когда это решение было принято.

Объяснение прозаично. Команда разработчиков никогда не была очень довольна синтаксисом инициализатора массива. Честно говоря, совершенно странно, что инициализатор массива не является выражением и синтаксически может появляться только в локальном или полевом объявлении. Это усложняет парсер. Кажется странным, что

int[] x = {1};

должен быть законным, но

M({1});

нет.

Синтаксис инициализации массива также упрощает восстановление ошибок во время анализа кода во время редактирования. Предположим, у вас есть что-то вроде:

class C
{
    void M()
    {
        {
            int result = whatever();
            ...
        }
        {
            int result = somethingElse();
            ...
        }
    }
}

и вы начинаете вводить новое объявление в редакторе:

    void M()
    {
        int[] x = 
        {
            int result = whatever();

и внезапно теперь синтаксический анализатор должен иметь дело с тем, чтобы устранить эту ситуацию так, чтобы не смутить бедного пользователя, который вот-вот наберет "null". Очевидно, что вы не собираетесь инициализировать локальную переменную блоком кода, но синтаксический анализатор совершенно в пределах своих прав сказать, что скобка может легально быть частью инициализатора массива здесь, и поэтому она является "результатом int", неожиданно.

Итак, длинный рассказ, "классические" инициализаторы массивов немного несовместимы. Мы не можем избавиться от них из-за соображений обратной совместимости. Но мы также не хотим поощрять их использование, позволяя им в большем количестве мест.

Команда разработчиков придумала идею добавления "new []" к инициализатору массива и превратила это в юридическое выражение, и теперь проблема решена. В новых областях языка нет "ползучести" классической неудачи инициализатора массива, и есть краткий, но читаемый синтаксис, в котором четко сказано "вы создаете новый массив здесь".

Мораль этой истории заключается в следующем: попробуйте сделать это правильно в первый раз, потому что синтаксис вечен.


(*) В моем поиске я обнаружил несколько интересных вещей: команда изначально считала, что "var", вероятно, не будет ключевым словом, выбранным для этой функции; по-видимому, они росли на них. Кроме того, один проект требует, чтобы локаторы "var" не просто были неявно напечатаны, но также были локалями init-once. Очевидно, что мы никогда не реализовывали локаторы init-once.

Ответ 2

Для этого можно использовать следующий синтаксис:

var words = new[] { "apple", "strawberry", "grape", "peach" };

Ответ 3

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

Однако это работает и выглядит так же, и это всего лишь пара символов.

var words = new[]{ "apple", "strawberry", "grape", "peach" };