Не можете использовать встроенный массив в C#?
Представь, что у тебя это где-то есть
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) я что-то упустил, как бы вы это сделали, если есть способ?
3 ответа
Вы должны сначала создать массив, используя 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
(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();
Я возвращаюсь к вопросам "почему нет", потому что, во-первых, ответы почти никогда не удовлетворяют - вы уже получили ответ "эта функция не так, как вы хотите, потому что спецификация не говорит то, что вы хотите сказать" Я думаю, что это не был особенно удовлетворительный ответ. Во-вторых, команде разработчиков не нужно объяснять, почему мир не такой, каким вы хотите его видеть; функции не существуют бесплатно и затем разрабатываются вне языка; скорее, функции должны быть сначала обоснованы, а затем разработаны в.
Итак, давайте попробуем сделать ваш вопрос "почему нет" немного более четким. Существующим признаком является то, что "инициализатор массива может использоваться (а) справа от равенства при инициализации или (б) справа от конструкции объекта типа массива". Предложенная особенность: "инициализатор массива также может использоваться как выражение". Вопрос в том, "что Эрик будет критиковать за предложенную функцию?"
Первая критика, которую я бы сделал, заключается в том, что неясно, что это за выражение. В инициализаторе переменной у вас есть тип переменной, а в выражении создания объекта - тип объекта; из них мы можем вывести тип построенного массива. Без какого-либо намека, какой тип мы должны вывести?
В 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, предлагаемая функция не имеет веских аргументов в пользу того, чтобы рекомендовать тратить на нее время, усилия и деньги на многие другие более достойные функции.
Поэтому такой функции нет.