Як ініціалізувати порожній масив у C #?


328

Чи можливо створити порожній масив без зазначення розміру?

Наприклад, я створив:

String[] a = new String[5];

Чи можемо ми створити вищевказаний масив рядків без розміру?


2
stackoverflow.com/questions/151936/… u перевірити це посилання, це може допомогти вам зрозуміти речі з масиву
Ravi Gadag

2
Також дивіться синтаксиси all-possible-c-
остро

Відповіді:


435

Якщо ви збираєтеся використовувати колекцію, яка не знаєш розмір заздалегідь, є кращі варіанти, ніж масиви.

Використовуйте List<string>натомість - це дозволить вам додати стільки елементів, скільки вам потрібно, і якщо вам потрібно повернути масив, зателефонуйте ToArray()на змінну.

var listOfStrings = new List<string>();

// do stuff...

string[] arrayOfStrings = listOfStrings.ToArray();

Якщо вам потрібно створити порожній масив, ви можете зробити це:

string[] emptyStringArray = new string[0]; 

1
@Oded - string [] emptyStringArray = новий рядок [0]; не призводить до порожнього масиву, чи не так? Схоже, це масив з одним елементом, де цей елемент є нульовим.
rory.ap

11
@roryap - Ні. Це призводить до того, string[]що немає елементів. Якщо ви спробуєте отримати доступ emptyStringArray[0], ви отримаєтеIndexOutOfRangeException
Oded

@Oded - Дякую, я досить новачок у C #. У VB наданий індекс - це верхня межа, а не кількість елементів.
rory.ap

1
Що б ви вважали краще: var strings = new string [] {}; або var string = нова рядок [0]; BTW: Я вважаю порожній масив абсолютно допустимим за замовчуванням для параметрів методу: public void EditItems (IEnumerable <Item> toEdit, IEnumerable <long> toDelete = new long [] {})
realbart

6
@ RickO'Shea - C ++ не є C #. Stroustrup знає свій C ++ - не настільки впевнений, що знає свої C # та .NET GC. Не збираюся з вами вступати в релігійну війну.
Oded

181

Спробуйте це:

string[] a = new string[] { };

7
Розгорнувши цю відповідь, ви також можете запустити масив з елементами, не вказуючи розмір АБО тип, компілятор буде робити висновок або з ініціалізатора: var a = new [] {"a", "b", "c"}; Це все ще сильно набраний рядковий масив.
Нік ВандерПейл

1
Неопрацьоване виняток: System.IndexOutOfRangeException: Index був поза межами масиву масиву. на ArrayClass.Main (String [] args). Я зіткнувся з цією помилкою після того, як я змінив свою змінну int [] = new int [] {}
yogesh

6
@yogesh: Це дивно. Наприклад, написання int[] variable = new int[]{}та використання його, наприклад, у циклі, такому як foreach (var s in variable){ Console.WriteLine(s);}код, компілюється в: int[] args1 = new int[0];і foreach (int num in args1){Console.WriteLine(num);}. Таким чином, не повинно бути різниці між використанням new int[0]і тим new int[]{}, що обидва збираються в один і той же код.
Nope

1
@GlennGordon Абсолютно, але це нове, ніж версія C # 3.0 (з 2007 року, з Visual Studio 2008). Ця версія також дозволяє інший простий формат з var, хоча тільки для локальних змінних (не для полів). Однак у C # 2.0 (Visual Studio 2005) та новіших версіях вам довелося використовувати синтаксис цієї відповіді (або string[] a = new string[0];).
Джеппе Стіг Нільсен

113

У .NET 4.6 кращим способом є використання нового методу Array.Empty:

String[] a = Array.Empty<string>();

Реалізація є лаконічною, використовуючи як статичні члени в загальних класах поводяться в .NET :

public static T[] Empty<T>()
{
    return EmptyArray<T>.Value;
}

// Useful in number of places that return an empty byte array to avoid
// unnecessary memory allocation.
internal static class EmptyArray<T>
{
    public static readonly T[] Value = new T[0];
}

(код, пов'язаний з контрактом, видалений для ясності)

Дивись також:


@Cole Johnson - Дякую за редагування, але я повернув його назад. Ці рядки я спеціально пропустив: хотів процитувати лише цікаву реалізацію. Код контракту та атрибути просто заважають зрозуміти, що відбувається (звичайно, у посиланні на джерело є все). До коментаря я також додав новий рядок, щоб уникнути прокрутки по переповненню стека. Якщо ви не заперечуєте, я вважаю за краще це. Дякую!
Кобі

2
Однозначно поліпшення для читабельності від:Enumerable.Empty<T>().ToArray()
DanielV

Незважаючи на те, що цей метод, безумовно, є переважним у більшості випадків, він не відповідає на початкове запитання. ОП хоче створити порожній масив. Array.Empty<T>()це НЕ створює масив. Він повертає посилання на попередньо виділений масив.
l33t

33

Ви можете ініціалізувати його з розміром 0, але вам доведеться повторно ініціалізувати його, коли знаєте, що таке розмір, оскільки ви не можете додати до масиву.

string[] a = new string[0];

Це точна відповідь
абзарак

7

В оголошенні масиву без розміру немає великого сенсу. Масив приблизно розміром . Коли ви оголошуєте масив конкретного розміру, ви вказуєте фіксовану кількість слотів, доступних у колекції, які вміщують речі, і відповідно розподіляється пам'ять. Щоб додати щось до нього, вам потрібно буде все-таки повторно ініціалізувати існуючий масив (навіть якщо ви змінюєте розмір масиву, див. Цю тему ). Одним з рідкісних випадків, коли ви хочете ініціалізувати порожній масив, буде передавати масив як аргумент.

Якщо ви хочете визначити колекцію, коли ви не знаєте, якого розміру вона може бути, можливо, масив - це не ваш вибір, а щось подібне List<T>чи подібне.

Однак, єдиний спосіб оголосити масив без зазначення розміру - мати порожній масив розміром 0 . Геманта і Алекса Дн надає два способи. Ще одна простіша альтернатива - це просто :

string[] a = { };

[ Елементи всередині дужки повинні бути неявно перетвореними у визначений тип, наприклад,string[] a = { "a", "b" }; ]

Або ще:

var a = Enumerable.Empty<string>().ToArray();

Ось більш декларативний спосіб :

public static class Array<T>
{
    public static T[] Empty()
    {
        return Empty(0);
    }

    public static T[] Empty(int size)
    {
        return new T[size];
    }
}

Тепер ви можете зателефонувати:

var a = Array<string>.Empty();

//or

var a = Array<string>.Empty(5);

1
Я не можу думати про будь-яке використання, крім випадків, коли вам потрібно передати масив як параметр. Є кілька випадків відображення, коли метод приймає масив об'єктів, і вам може знадобитися передати порожній масив, щоб здійснити дію за замовчуванням. Я відредагую свою відповідь.
nawfal

Наприклад, у вас є інтерфейс, реалізований декількома класами, що повертають IEnumerable, і одна з реалізацій не містить елементів методу, і, наприклад, повертає порожній масив.
Ігнасіо Солер Гарсія

@IgnacioSolerGarcia Я б повернув масив у такому випадку, якщо і лише в тому випадку, якщо це надзвичайно важлива ефективність програми. Я скажу, що масиви застаріли, і, якщо можете, слід уникати їх. Дивіться це Ліпперт і це питання ТАК
nawfal

Майте на увазі, що тип, що повертається, є IEnumerable, тому масив є лише для читання, і він не має наміру змінюватися. Чому я, наприклад, повертаю Список у такому випадку?
Ігнасіо Солер Гарсія

1
Випадок використання порожнього масиву простий - коли ви хочете заповнити його об'єктами, і ви не знаєте, скільки ви додасте!
vapcguy

6

Просто і елегантно!

string[] array = {}

Я б змінив arrayна просто a, як arrayце ключове слово, коли з великої літери. Просто погана практика використовувати ім'я ключового слова в якості імені змінної - навіть якщо випадок відрізняється. І в основному те саме, що моя відповідь, за винятком того, що я був String.Emptyтам.
vapcguy

1
1. масив не є ключовим словом ac #. Масив - це клас, а не ключове слово 2. "а" - це також погана практика (можливо, ще гірша погана практика, ніж використання ключових слів)
disklosr

Будучи технічним. Клас, ключове слово, він визначає тип об'єкта і все ще поганий. Чому ви вважаєте aпоганим?
vapcguy

1
Тому що не описові і однобуквені назви змінних є поганою практикою, оскільки вони не пояснюють причину їх визначення. "масив", безумовно, краще ім'я, ніж "а". Кращою назвою було б "emptyArray".
disklosr

4

string[] a = new string[0];

або коротке позначення:

string[] a = { };

Зараз кращим способом є:

var a = Array.Empty<string>();

Я написав короткий регулярний вираз , яке можна використовувати в Visual Studio , якщо ви хочете замінити нульову довжину розподіл наприклад new string[0]. Використовуйте Find (пошук) у Visual Studio із увімкненою опцією Regular Expression:

new[ ][a-zA-Z0-9]+\[0\]

Тепер знайдіть усіх або F3 (Знайдіть далі) і замініть всі на Array.Empty <…> ()!


3

Ви можете визначити розмір масиву під час виконання .

Це дозволить вам зробити що завгодно, щоб динамічно обчислити розмір масиву. Але, як тільки визначений розмір, непорушний.

Array a = Array.CreateInstance(typeof(string), 5);

4
Навіщо все це робити? Під час виконання ви можете визначати розмір масиву зі змінної, як правило:int i = 5; string[] a = new string[i];
Кевін Брок

Ну, я думаю, що з дженериками це видається застарілим.
radarbob

2

Я намагався:

string[] sample = new string[0];

Але я міг вставити в неї лише один рядок, і тоді я отримав errorOutOfBound помилку, тому я просто поставив для неї розмір, як

string[] sample = new string[100];

Або інший спосіб, який працює для мене:

List<string> sample = new List<string>();

Призначення значення списку:

sample.Add(your input);

1

Як я знаю, ви не можете створити масив без розміру, але ви можете використовувати

List<string> l = new List<string>() 

а потім l.ToArray().


1

Поєднання пропозицій @nawfal та @Kobi:

namespace Extensions
{
    /// <summary> Useful in number of places that return an empty byte array to avoid unnecessary memory allocation. </summary>
    public static class Array<T>
    {
        public static readonly T[] Empty = new T[0];
    }
}

Приклад використання:

Array<string>.Empty

ОНОВЛЕННЯ 2019-05-14

(кредити @Jaider ty)

Краще використовувати .Net API:

public static T[] Empty<T> ();

https://docs.microsoft.com/en-us/dotnet/api/system.array.empty?view=netframework-4.8

Відноситься до:

.NET Core: 3.0 Попередній перегляд 5 2.2 2.1 2.0 1.1 1.0

.NET Framework: 4.8 4.7.2 4.7.1 4.7 4.6.2 4.6.1 4.6

.NET Standard: 2.1 Попередній перегляд 2.0 1.6 1.5 1.4 1.3

...

HTH


1
У .NET Core 2 для нього вже є розширення,arr = Array.Empty<string>();
Jaider

iirc, в .NetStandart [4.щось] - теж є.
ShloEmi

0

Ви можете зробити:

string[] a = { String.Empty };

Примітка: ОП означало, що не потрібно вказувати розмір, а не робити масив нерозмірним


7
Чи не створить це рядковий масив довжиною 1?
Самнер Еванс

Щоправда, але це очищено. І ОП попросив оголосити масив без зазначення розміру - це підходить.
vapcguy

І це заслуговує на голосування, чому? OP означав, що не має specifyрозміру, не створює масив sizeless.
vapcguy

1
@vapcguy Я був прихильником. Я шкодую про це. Я відредагував вашу відповідь, щоб скасувати свій запис. Ваш коментар робить питання трохи сумнівним. Не впевнений, чи означає це ОП.
nawfal

4
ОП попросив порожній масив. Цей масив не порожній.
Кіт

0

Ось приклад справжнього світу. У цьому необхідно ініціалізувати масив foundFilesспочатку до нульової довжини.

(Як наголошено в інших відповідях: Це ініціалізує не елемент, а особливо не елемент з індексом нуля, тому що це означатиме, що масив мав довжину 1. Масив має нульову довжину після цього рядка!).

Якщо частина = string[0]опущена, виникає помилка компілятора!

Це через блок вилову без повторного відкидання. Компілятор C # розпізнає шлях коду, що функція Directory.GetFiles()може кинути виняток, щоб масив міг бути неініціалізованим.

Перш ніж хтось скаже, не повторне скидання винятку було б поганим поводженням з помилками: Це неправда. Помилка керування повинна відповідати вимогам.

У цьому випадку передбачається, що програма повинна продовжуватися у випадку, якщо каталог не може бути прочитаний і не розбитий - найкращим прикладом є функція, що проходить через структуру каталогу. Тут обробка помилок - це просто її реєстрація. Звичайно, це можна зробити краще, наприклад, зібрати всі GetFiles(Dir)списки каталогів з невдалими дзвінками в список, але це призведе сюди занадто далеко.

Досить констатувати, що уникнення throwє допустимим сценарієм, і тому масив повинен бути ініціалізований до нульової довжини. Було б достатньо зробити це в блоці ловлі, але це був би поганий стиль.

Виклик зміни GetFiles(Dir)розміру масиву.

string[] foundFiles= new string[0];
string dir = @"c:\";
try
{
    foundFiles = Directory.GetFiles(dir);  // Remark; Array is resized from length zero
}
// Please add appropriate Exception handling yourself
catch (IOException)
{
  Console.WriteLine("Log: Warning! IOException while reading directory: " + dir);
  // throw; // This would throw Exception to caller and avoid compiler error
}

foreach (string filename in foundFiles)
    Console.WriteLine("Filename: " + filename);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.