Представьте, что это где-то есть
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) я что-то упускаю, как бы вы это сделали, если есть способ?
Ответы:
Сначала вам нужно создать массив, используя
new[]
.string letter = (new[] {"a","b","c"}).AnyOne();
Как упоминал @hvd, вы можете сделать это без скобок
(..)
, я добавил скобки, потому что считаю, что это более читабельно.string letter = new[] {"a","b","c"}.AnyOne();
И вы можете указать тип данных,
new string[]
как упоминалось в других ответах.Вы не можете просто сделать это
{"a","b","c"}
, потому что вы можете думать об этом как о способе заполнения массива, а не для его создания.Другая причина будет заключаться в том, что компилятор запутается, не будет знать, что создать, например, a
string[]{ .. }
или aList<string>{ .. }
.Используя только
new[]
компилятор, можно узнать по типу данных (".."
){..}
, что вы хотите (string
). Важная часть состоит в том[]
, что вам нужен массив.Вы даже не можете создать пустой массив с помощью
new[]
.string[] array = new []{ }; // Error: No best type found for implicity-typed array
источник
string letter = new[] {"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"}"
само по себе без использования в объявлении ничего не значит. Следовательно, вы не можете использовать его с вашим методом расширения, поскольку ваш метод расширения работает с массивом.Уже упоминавшийся в @ 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, предлагаемая функция не имеет веских аргументов в пользу того, чтобы рекомендовать тратить на нее время, усилия и деньги вместо многих других более достойных функций.
Следовательно, такой особенности нет.
источник