Не можете использовать массив "inline" в С#?
Представьте, что у вас есть это где-то
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) я что-то упустил, как бы вы это сделали, если есть способ?
Ответы
Ответ 1
Сначала нужно создать массив, используя new[]
.
string letter = (new[] {"a","b","c"}).AnyOne();
Как упоминалось в @hvd, вы можете сделать это без скобок (..)
, я добавил скобки, потому что считаю это более читаемым.
string letter = new[] {"a","b","c"}.AnyOne();
И вы можете указать тип данных new string[]
, как и в других ответах.
Вы не можете просто сделать {"a","b","c"}
, потому что вы можете думать об этом как о способе заполнения массива, а не о его создании.
Другая причина заключается в том, что компилятор будет запутан, не знает, что создавать, например, string[]{ .. }
или List<string>{ .. }
.
Используя только new[]
, компилятор может узнать по типу данных (".."
) между {..}
, что вы хотите (string
). Существенной частью является []
, это означает, что вам нужен массив.
Вы даже не можете создать пустой массив с new[]
.
string[] array = new []{ }; // Error: No best type found for implicity-typed array
Ответ 2
(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 объясняется выражение Creation Creation в спецификации языка С#.
Таким образом, этот "{"a", "b", "c"}"
один без использования в объявлении ничего не значит. Следовательно, вы не можете использовать его с вашим методом расширения, поскольку ваш метод расширения работает с массивом.
(2) Я что-то упустил, как бы вы это сделали, если есть способ?
Уже упоминается в @adricadar answer, вы можете сделать:
(new[] {"a","b","c"}).AnyOne();
или
(new string[] {"a","b","c"}).AnyOne();
Ответ 3
Я возвращаюсь к "почему не", потому что во-первых, ответы почти никогда не удовлетворяются - вы уже получили ответ "функция не так, как вы этого хотите, потому что спецификация не говорит, что вы хотите сказать", что, на мой взгляд, не является особенно удовлетворительным ответом. Во-вторых, команда дизайнеров не должна оправдывать, почему мир не так, как вы этого хотите; функции не существуют бесплатно, а затем создаются из языка; скорее, функции должны быть сначала оправданы, а затем разработаны.
Итак, постарайтесь сделать ваш вопрос "почему бы" немного более четким. Существующая функция: "инициализатор массива может использоваться (а) в правой части равных в инициализации или (б) справа от построения объекта типа массива". Предлагаемая функция: "инициализатор массива также может использоваться как выражение". Вопрос в том, "какие критические замечания сделал бы Эрик из предложенной функции?"
Первая критика, которую я сделаю, заключается в том, что неясно, каков тип выражения. В переменном инициализаторе у вас есть тип переменной, и в выражении создания объекта у вас есть тип объекта; из обоих мы можем вывести тип сконструированного массива. Без какого-либо намека, какой тип мы должны вывести?
В С# 1.0, когда эта функция была добавлена, было получено полное количество нулевых умозаключений, сделанных на этом языке. Принцип дизайна в первые дни С# был "без сюрпризов" и что компилятор не был "слишком умным". Если разработчик предполагает, что выражение имеет конкретный тип, этот тип должен быть каким-то образом очевидным в выражении. Когда вы скажете
new double[] { 1, 2, 3.4 }
довольно ясно, какой тип предназначен. Аналогично
new Animal[] { cat, dog, null }
Предлагаемая функция нарушает этот принцип. Выражение должно иметь тип, но отнюдь не ясно, какой тип аргумента находится в
M({cat, dog, null})
Кроме того: предположим, что у нас есть две перегрузки M
, один из которых принимает массив Animal
и тот, который принимает массив IPet
. Какая перегрузка M
применима? Является ли одно из преобразований лучше, чем другое? Типы элементов Cat
и Dog
; имеет ли смысл вывести тип, который даже не появляется там? Это все вопросы, которые должны быть рассмотрены командой дизайнеров, и это вопросы, которые отнюдь не являются очевидными ответами. Предлагаемая особенность ведет нас в глубокие воды в довольно коротком порядке.
Теперь С# 3.0 решает эту проблему, потому что С# 3.0 добавил множество функций, в которых компилятор записывает типы от имени разработчика. Предыдущие принципы "без сюрпризов" и "простых правил" противоречили другим принципам проектирования, необходимым для работы LINQ. Если предлагаемая вами функция была добавлена в С# 3.0?
Это могло быть. Функция, добавленная в С# 3.0, была:
new[] { x, y, z }
указывает тип массива с использованием алгоритма: возьмите выражения для элементов, которые имеют типы, определите, какой из этих типов является единственным наиболее общим типом, к которому конвертируются все остальные выражения, и если такой тип существует, выберите что. В противном случае возникает ошибка,
Эта функция могла быть еще более расслабленной, чтобы сделать new[]
опциональным. Это не было сделано.
Теперь, если бы вы попросили меня в С# 3.0 таймфрейма критиковать предложенную функцию, я бы указал, что (1) компилятор С# 3.0 был уже в серьезной опасности соскользнуть с расписанием на весь выпуск, поэтому пусть не добавьте больше усилий по разработке, внедрению и тестированию для полностью ненужной функции, которая сохраняет пользовательские клавиши шесть, и (2) С# 3.0 также добавили инициализаторы коллекции:
new List<int>() { 10, 20, 30 }
зачем {10, 20, 30}
автоматически быть массивом? Почему это не должно быть List<int>
? Или любой из нескольких других типов? Почему предвзятость к массивам? Помните, , когда мы решили закрепить синтаксис для массивов, мы застряли с ним навсегда. Это никогда не может быть чем-то еще, поэтому предлагаемая функция не только не нужна, но и предотвращает возможные возможные функции, которые кажутся правдоподобными.
Подведение итогов: предлагаемая функция напрямую нарушала некоторые принципы проектирования С# 1.0. Он добавляет ничего, кроме ненужного бремени для С# 3.0. Во всех версиях языка с С# 3.0 предлагаемая функция не имеет хороших аргументов, чтобы рекомендовать потратить время, усилия и деньги на нее по многим другим более достойным функциям.
Следовательно, такой функции нет.