Как инициализировать пустой массив в C #?

328

Можно ли создать пустой массив без указания размера?

Например, я создал:

String[] a = new String[5];

Можем ли мы создать массив строк без размера?

Йогеш
источник
2
stackoverflow.com/questions/151936/… u проверьте эту ссылку, она может помочь вам ясно понять вещи массива
Ravi Gadag

Ответы:

436

Если вы собираетесь использовать коллекцию, размер которой заранее не известен, есть лучшие варианты, чем массивы.

Используйте List<string>вместо этого - это позволит вам добавить столько элементов, сколько вам нужно, и, если вам нужно вернуть массив, вызовите ToArray()переменную.

var listOfStrings = new List<string>();

// do stuff...

string[] arrayOfStrings = listOfStrings.ToArray();

Если вам нужно создать пустой массив, вы можете сделать это:

string[] emptyStringArray = new string[0]; 
Одед
источник
1
@Oded - строка [] emptyStringArray = новая строка [0]; не приводит к пустому массиву, не так ли? Похоже, что это массив с одним элементом, где этот элемент равен нулю.
rory.ap
11
@roryap - Нет. Это приводит к тому, string[]что не имеет элементов. Если вы попытаетесь получить доступ emptyStringArray[0], вы получитеIndexOutOfRangeException
Одед
@Oded - Спасибо, я довольно новичок в C #. В VB указанным индексом является верхняя граница, а не количество элементов.
rory.ap
1
Что бы вы посчитали лучше: var strings = new string [] {}; или var strings = новая строка [0]; Кстати: я считаю пустой массив совершенно допустимым значением по умолчанию для параметров метода: public void EditItems (IEnumerable <Item> toEdit, IEnumerable <long> toDelete = new long [] {})
realbart
6
@ RickO'Shea - C ++ не является C #. Страуструп знает свой C ++ - не уверен, что он знает свой C # и .NET GC. Не собираюсь вступать в религиозную войну с тобой.
Одед
182

Попробуй это:

string[] a = new string[] { };
Hemant
источник
7
Расширяя этот ответ, вы также можете инициировать массив с элементами без указания размера ИЛИ типа, компилятор выведет либо из инициализатора: var a = new [] {"a", "b", "c"}; Это все еще строго типизированный массив строк.
Ник ВандерПайл
1
Необработанное исключение: System.IndexOutOfRangeException: индекс находился за пределами границ массива. в 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[]{}что оба компилируются в один и тот же код.
Нет
1
@GlennGordon Абсолютно, но это новое с версии C # 3.0 (с 2007 года, с Visual Studio 2008). Эта версия также допускает другой простой формат с var, хотя только для локальных переменных (не для полей). Однако в C # 2.0 (Visual Studio 2005) и более ранних версиях вам пришлось использовать синтаксис этого ответа (или string[] a = new string[0];).
Джеппе Стиг Нильсен
114

В .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 - Спасибо за редактирование, но я откатился назад. Я специально пропустил эти строки: я хотел процитировать только интересную реализацию. Контракт кода и атрибуты только мешают понять, что происходит (ссылка на источник имеет все, конечно). Я также добавил новую строку в комментарии, чтобы избежать прокрутки Stack Overflow. Если вы не возражаете, я предпочитаю это так. Спасибо!
Коби
2
Определенно улучшение для читабельности от:Enumerable.Empty<T>().ToArray()
DanielV
Хотя этот метод определенно предпочтителен в большинстве случаев, он не отвечает на первоначальный вопрос. ОП хочет создать пустой массив. Array.Empty<T>()это не создает массив. Возвращает ссылку на предварительно выделенный массив.
l33t
33

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

string[] a = new string[0];
MatthiasG
источник
Это точный ответ
абзарак
7

Нет особого смысла объявлять массив без размера. Массив имеет размер . Когда вы объявляете массив определенного размера, вы указываете фиксированное количество слотов, доступных в коллекции, которая может содержать объекты, и, соответственно, выделяется память. Чтобы что-то добавить к нему, вам все равно нужно будет повторно инициализировать существующий массив (даже если вы изменяете размер массива, см. Эту ветку ). Одним из редких случаев, когда вы хотите инициализировать пустой массив, является передача массива в качестве аргумента.

Если вы хотите определить коллекцию, когда вы не знаете, какого размера она может быть, массив - это не ваш выбор, а что-то вроде a 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 = {}
disklosr
источник
Я бы изменил arrayна просто a, как arrayэто ключевое слово, когда оно пишется с большой буквы. Просто плохая практика использовать ключевое слово в качестве имени переменной - даже если дело обстоит иначе. И в основном такой же, как мой ответ, кроме меня String.Emptyтам.
vapcguy
1
1. массив не является ключевым словом ac #. Массив - это класс, а не ключевое слово 2. «а» также плохая практика (может быть, даже хуже, чем использование ключевых слов)
disklosr
Быть техническим. Класс, ключевое слово, он определяет тип объекта и все еще плох. Почему вы думаете, aэто плохо?
vapcguy
1
Потому что неописательные и однобуквенные имена переменных являются плохой практикой, потому что они не передают причину их определения. «массив», безусловно, лучше, чем «а». Лучшее имя будет "emptyArray".
дисклоср
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\]

Теперь Find All или F3 (Find Next) и замените все на Array.Empty <…> ()!

ЮФО
источник
3

Вы можете определить размер массива во время выполнения .

Это позволит вам делать что угодно для динамического вычисления размера массива. Но, однажды определенный размер неизменен.

Array a = Array.CreateInstance(typeof(string), 5);
radarbob
источник
4
Зачем все это? Во время выполнения вы можете определить размер массива из переменной обычно:int i = 5; string[] a = new string[i];
Кевин Брок
Ну, я думаю, с дженериками это кажется устаревшим.
Радар Боб
2

Я пытался:

string[] sample = new string[0];

Но я мог вставить в него только одну строку, а затем я получил ошибку исключения OutOfBound, поэтому я просто добавил для него размер, например

string[] sample = new string[100];

Или другой способ, который работает для меня:

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

Назначение значения для списка:

sample.Add(your input);
Cs_Lu
источник
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 Preview 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 Preview 2.0 1.6 1.5 1.4 1.3

...

НТН

ShloEmi
источник
1
В .NET Core 2 уже есть расширение для него,arr = Array.Empty<string>();
Jaider
iirc, в .NetStandart [4.something] - тоже есть.
ShloEmi
0

Ты можешь сделать:

string[] a = { String.Empty };

Примечание: OP означает, что нет необходимости указывать размер, а не делать массив без размера

vapcguy
источник
8
Не приведет ли это к созданию массива строк длиной 1?
Самнер Эванс
Правда, но это очищено. И ОП попросил объявить массив без указания размера - это подходит для этого.
vapcguy
И это заслуживает отрицательного ответа, почему? ОП означало отсутствие specifyразмера, а не создание массива sizeless.
vapcguy
1
@vapcguy Я был даунотером. Я сожалею об этом. Я отредактировал ваш ответ, чтобы отменить мое понижение. Ваш комментарий делает вопрос немного сомнительным. Не уверен, что именно это имел в виду OP.
Nawfal
4
ОП запросил пустой массив. Этот массив не пустой.
Кит
0

Вот пример из реального мира. При этом необходимо инициализировать массив foundFilesсначала нулевой длиной.

(Как подчеркивалось в других ответах: это инициализирует не элемент и особенно не элемент с нулевым индексом, потому что это будет означать, что массив имеет длину 1. Массив имеет нулевую длину после этой строки!).

Если часть = string[0]не указана, возникает ошибка компилятора!

Это из-за блока захвата без повторного выброса. Компилятор C # распознает путь к коду, что функция Directory.GetFiles()может выдать исключение, чтобы массив мог быть неинициализирован.

Прежде чем кто-то скажет, не выбрасывать исключение было бы плохой обработкой ошибок: это не так. Обработка ошибок должна соответствовать требованиям.

В этом случае предполагается, что программа должна продолжаться в случае каталога, который не может быть прочитан и не прерван - лучшим примером является функция, проходящая через структуру каталога. Здесь обработка ошибок просто регистрирует это. Конечно, это можно сделать лучше, например, собрать все каталоги с ошибочными GetFiles(Dir)вызовами в списке, но это приведет к этому слишком далеко.

Достаточно сказать, что избегание throwявляется допустимым сценарием, и поэтому массив должен быть инициализирован до нулевой длины. Этого было бы достаточно, чтобы сделать это в блоке catch, но это был бы плохой стиль.

Вызов 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);
Philm
источник