Не можете использовать «встроенный» массив в C #?

92

Представьте, что это где-то есть

public static T AnyOne<T>(this T[] ra) where T:class
    {
    int k = ra.Length;
    int r = Random.Range(0,k);
    return ra[r];
    }

или даже просто это

public static string OneOf(this string[] strings)
    {
    return "a";
    }

Тогда, конечно, ты сможешь это сделать ...

string[] st = {"a","b","c"};
string letter = st.AnyOne();

... и это здорово. НО. Похоже, вы НЕ МОЖЕТЕ этого сделать:

string letter = {"a","b","c"}.AnyOne();

или, возможно, это

string letter = ( {"a","b","c"} ).AnyOne();

или что-нибудь еще, что я пробовал.

Фактически (1) почему нельзя этого сделать? и (2) я что-то упускаю, как бы вы это сделали, если есть способ?

Толстяк
источник
5
Я не уверен, что повторяющийся вопрос уместен, OP не спрашивает об инициализаторах массива, но почему компилятор не распознает объект как массив, пока он не будет назначен.
Рон Бейер
4
Я не знаком с терминологией C #, но считаю, что это чаще называют литералом или литералом массива, а не встроенным .
Чи
3
Этот синтаксический элемент является инициализатором массива или инициализатором коллекции , в зависимости от контекста, в котором он используется. Ни в том, ни в другом случае это не классифицируется как выражение .
Эрик Липперт

Ответы:

133

Сначала вам нужно создать массив, используя new[].

string letter = (new[] {"a","b","c"}).AnyOne();

Как упоминал @hvd, вы можете сделать это без скобок (..), я добавил скобки, потому что считаю, что это более читабельно.

string letter = new[] {"a","b","c"}.AnyOne();

И вы можете указать тип данных, new string[]как упоминалось в других ответах.


Вы не можете просто сделать это {"a","b","c"}, потому что вы можете думать об этом как о способе заполнения массива, а не для его создания.

Другая причина будет заключаться в том, что компилятор запутается, не будет знать, что создать, например, a string[]{ .. }или a List<string>{ .. }.

Используя только new[]компилятор, можно узнать по типу данных ( "..") {..}, что вы хотите ( string). Важная часть состоит в том [], что вам нужен массив.

Вы даже не можете создать пустой массив с помощью new[].

string[] array = new []{ }; // Error: No best type found for implicity-typed array
адрикадар
источник
13
Вам не нужны эти скобки. string letter = new[] {"a","b","c"}.AnyOne();просто отлично. Если вы хотите их, если вы думаете, что это более читабельно с круглыми скобками, они действительны, но в этом случае я думаю, что по крайней мере стоит упомянуть, что это осознанный выбор с вашей стороны, что он не был навязан языком.
Я знаю о синтаксисе new [] {1,2}, но есть ли еще более простой синтаксис? Что-то вроде [1, 2]?
seguso
51

(1) почему нельзя этого сделать? {"a","b","c"}.AnyOne();

Эта строка:

string[] st = {"a","b","c"};

это сокращение для эквивалентного выражения создания массива ILSpy )

string[] st = new string[]  {"a","b","c"};

Это string[] st = {"a","b","c"} можно использовать только во время объявления , вы не можете не использовать его где-либо еще, вы даже не можете:

string[] st;
st = {"a", "b", "c"}; //Error

Это объясняется в разделе 7.6.10.4 для выражения создания массива в спецификациях языка C #.

Так что это "{"a", "b", "c"}"само по себе без использования в объявлении ничего не значит. Следовательно, вы не можете использовать его с вашим методом расширения, поскольку ваш метод расширения работает с массивом.

(2) я что-то упускаю, как бы вы это сделали, если есть способ?

Уже упоминавшийся в @ adricadar в ответ , вы можете сделать:

(new[] {"a","b","c"}).AnyOne();

или

(new string[] {"a","b","c"}).AnyOne();
Хабиб
источник
48

Я возвращаюсь к вопросам «почему бы и нет», потому что, во-первых, ответы почти никогда не бывают удовлетворительными - вы уже получили ответ «функция не такая, как вы хотите, потому что в спецификации не сказано, что вы хотите, чтобы она говорила» , который, как мне кажется, не был особенно удовлетворительным ответом. Во-вторых, команде дизайнеров не нужно объяснять, почему мир не такой, каким вы хотите его видеть; функции не существуют бесплатно, а затем создаются вне языка; скорее, функции должны быть сначала обоснованы, а затем разработаны.

Так что давайте постараемся сделать ваш вопрос «почему бы и нет» более четким. Существующая особенность заключается в том, что «инициализатор массива может использоваться (а) справа от равенства при инициализации или (б) справа от конструкции объекта типа массива». Предлагаемая особенность: «инициализатор массива также может использоваться как выражение». Вопрос в том, «какую критику Эрик высказал бы по поводу предлагаемой функции?»

Первая критика, которую я хотел бы сделать, это то, что неясно, каков тип выражения. В инициализаторе переменной у вас есть тип переменной, а в выражении создания объекта - тип объекта; по обоим из них мы можем определить тип построенного массива. Без каких-либо намеков, какой тип мы должны вывести?

В C # 1.0, когда эта функция была добавлена, в языке было сделано в общей сложности нулевые выводы типа. Принцип проектирования в первые дни C # был «без сюрпризов», а компилятор не был «слишком умным». Если разработчик хочет, чтобы выражение было определенного типа, этот тип должен быть каким-то образом очевиден в выражении. Когда ты говоришь

new double[] { 1, 2, 3.4 }

довольно ясно, какой тип предназначен. по аналогии

new Animal[] { cat, dog, null }

Предлагаемая функция нарушает этот принцип. Выражение должно иметь тип, но отнюдь не ясно, какой тип аргумента находится в

M({cat, dog, null})

Более того: предположим, что у нас есть две перегрузки M, одна из которых принимает массив, Animalа другая - массив IPet. Какая перегрузка Mприменима? Одно из преобразований лучше другого? Типы элементов: Catи Dog; имеет ли смысл выводить тип, которого там даже нет? Это все вопросы, которые должны быть рассмотрены командой разработчиков, и это вопросы, на которые нет очевидных ответов. Предлагаемая особенность очень быстро приводит нас в глубокие воды.

Теперь C # 3.0 решает эту проблему, потому что в C # 3.0 добавлены многочисленные функции, в которых компилятор определяет типы от имени разработчика. Предыдущие принципы «без сюрпризов» и «простые правила» противоречили другим принципам проектирования, необходимым для работы LINQ. Следует ли добавить предлагаемую вами функцию в C # 3.0?

Это могло бы быть. Фактически добавленная в C # 3.0 функция была:

new[] { x, y, z }

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

Эту функцию можно было бы упростить, сделав ее new[]необязательной. Этого не было сделано.

Теперь, если бы вы попросили меня во временных рамках C # 3.0 критиковать предлагаемую функцию, я бы указал, что (1) компилятор C # 3.0 уже находился в серьезной опасности смещения графика для всего выпуска, поэтому давайте не будем больше добавлять бремя проектирования, реализации и тестирования совершенно ненужной функции, которая экономит пользователю шесть нажатий клавиш, и (2) C # 3.0 также добавил инициализаторы коллекций:

new List<int>() { 10, 20, 30 }

почему {10, 20, 30}автоматически должен быть массив ? Почему не должно быть List<int>? Или любой из множества других типов? Почему уклон в сторону массивов? Помните, что если мы решили закрепить синтаксис для массивов, мы застряли с ним навсегда . Это может никогда не быть чем - то другим, поэтому предлагаемая функция не только не нужна, но и предотвращает возможные будущие функции, которые кажутся правдоподобными.

Подводя итог: предлагаемая функция прямо нарушает некоторые принципы проектирования C # 1.0. Он не добавляет в C # 3.0 ничего, кроме ненужной нагрузки. Во всех версиях языка, начиная с C # 3.0, предлагаемая функция не имеет веских аргументов в пользу того, чтобы рекомендовать тратить на нее время, усилия и деньги вместо многих других более достойных функций.

Следовательно, такой особенности нет.

Эрик Липперт
источник
Хех, тебе нужно напечатать футболку с надписью «мир не такой, каким ты хочешь его видеть» :)
slugster
6
@JoeBlow: Во-первых, добро пожаловать. Что касается «почему бы и нет?» - ваш комментарий хорошо иллюстрирует проблему. Когда некоторые люди задают вопрос «почему», они ищут логическое оправдание . Некоторые ищут прагматического оправдания . И вы, видимо, ищете строку спецификации, описывающую правило . Это настолько расплывчато, что очень сложно сформулировать хороший ответ, который нацелен на вопрос, действительно находящийся в уме задающего вопрос. Вопросы «Почему бы и нет» еще хуже, потому что это расплывчатые вопросы о вещах, которых даже не существует .
Эрик Липперт
3
@EricLippert Это даже хуже, чем просто вопрос о вещах, которые _могут_ существовать : если вы работаете над программным обеспечением в команде, вся команда тратит каждый день в году на размышления о функциях и балансировку последствий. Решения принимаются. Запросы функций и «почему» требует обоснования. Однако « почему не» подразумевает, что кто-то просто хочет, чтобы что-то было сделано, что в основном ставит под сомнение суждение самой команды. Хуже того, человек, задающий вопрос « Почему бы и нет», обычно мало знает о предмете. Таким образом, я думаю, что отказ от вопросов, почему бы и нет, совершенно справедливо. Хорошая работа, ИМО.
atlaste