Подтвердить что ты не робот

Не можете использовать массив "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) я что-то упустил, как бы вы это сделали, если есть способ?

4b9b3361

Ответ 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 предлагаемая функция не имеет хороших аргументов, чтобы рекомендовать потратить время, усилия и деньги на нее по многим другим более достойным функциям.

Следовательно, такой функции нет.