Не можете використовувати вбудований масив у 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
Цей синтаксичний елемент є ініціалізатором масиву або ініціалізатором збору , залежно від контексту, в якому він використовується. У жодному випадку це не класифікується як вираз .
Ерік Ліпперт,

Відповіді:


132

Спочатку потрібно створити масив, використовуючи 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 для виразу Array Creation у специфікаціях мови 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, запропонована функція не має вагомих аргументів, щоб рекомендувати витрачати на це час, зусилля та гроші на багато інших більш гідних функцій.

Тому такої особливості немає.


Хе, вам потрібно надрукувати футболку з
написом

6
@JoeBlow: По-перше, вас дуже вітаємо. Щодо "чому ні" - ваш коментар добре ілюструє проблему. Коли деякі люди задають питання «чому», вони шукають логічне обґрунтування . Деякі люди шукають прагматичного виправдання . І ви, мабуть, шукаєте рядок специфікації, що описує правило . Це настільки розмито, що дуже важко скласти хорошу відповідь, яка націлена на питання насправді в свідомості допитувача. Питання "чому б і ні" ще гірші, бо це невиразні запитання про речі, яких навіть не існує .
Ерік Ліпперт,

3
@EricLippert Це навіть гірше, ніж просто питання про речі, які _можуть_ існувати : якщо ви працюєте над програмним забезпеченням разом із командою, вся команда витрачає кожен день в році на роздуми про функції та балансування наслідків. Приймаються рішення. Запити щодо функцій та запитання "чому" вимагає обґрунтування. Однак чому б це не означало, що хтось просто хоче чогось зробити, що в основному ставить під сумнів судження самої команди. Гірше того, що людина, яка задає питання, чому не, зазвичай мало що знає про цю тему. Як такий, я думаю, що відштовхування, чому не питання, є цілком справедливим. Хороша робота IMO.
атлас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.