Почему я не могу использовать инициализатор массива с неявно типизированной переменной? - PullRequest
15 голосов
/ 08 сентября 2011

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

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

Это только добавляет мне путаницы. И «это так, потому что в спецификации так сказано» мало что поможет. Почему спецификация такая? Каково здесь обоснование?

Ответы [ 3 ]

33 голосов
/ 09 сентября 2011

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

Я не был в команде разработчиков, когда было принято это решение, и в примечаниях к дизайну (*) об этом ничего не говорится. Однако я спросил кого-то, кто был в комнате в 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.

5 голосов
/ 08 сентября 2011

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

var words = new[] { "apple", "strawberry", "grape", "peach" };
4 голосов
/ 08 сентября 2011

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

Тем не менее, это работает и выглядит одинаково и просто на пару символов длиннее.

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