Jak zainicjować pustą tablicę w C #?

Odpowiedzi:

435

Jeśli zamierzasz użyć kolekcji, której nie znasz z góry, istnieją lepsze opcje niż tablice.

Użyj List<string>zamiast tego - pozwoli ci dodać tyle elementów, ile potrzebujesz, a jeśli musisz zwrócić tablicę, wywołaj ToArray()zmienną.

var listOfStrings = new List<string>();

// do stuff...

string[] arrayOfStrings = listOfStrings.ToArray();

Jeśli musisz utworzyć pustą tablicę, możesz to zrobić:

string[] emptyStringArray = new string[0]; 
Oded
źródło
1
@Oded - string [] emptyStringArray = nowy ciąg [0]; nie powoduje pustej tablicy, prawda? Wygląda na to, że jest to tablica z jednym elementem, w którym element ten ma wartość NULL.
rory.ap
11
@roryap - Nie. Powoduje to, string[]że nie ma elementów. Jeśli spróbujesz uzyskać dostęp emptyStringArray[0], otrzymaszIndexOutOfRangeException
Oded
@Oded - Dzięki, jestem całkiem nowy w C #. W VB podany indeks jest górną granicą, a nie liczbą elementów.
rory.ap
1
Co uważasz za lepsze: var strings = new string [] {}; lub var strings = nowy ciąg [0]; BTW: Uważam pustą tablicę za całkowicie poprawną wartość domyślną dla parametrów metody: public void EditItems (IEnumerable <Item> toEdit, IEnumerable <long> toDelete = new long [] {})
realbart
6
@ RickO'Shea - C ++ nie jest C #. Stroustrup zna swój C ++ - nie jestem pewien, czy zna swój C # i .NET GC. Nie pójdę z tobą na wojnę religijną.
Oded
181

Spróbuj tego:

string[] a = new string[] { };
hemant
źródło
7
Rozwijając tę ​​odpowiedź, możesz również zainicjować tablicę elementami bez określania rozmiaru LUB typu, kompilator wywnioskuje albo z inicjalizatora: var a = new [] {"a", "b", "c"}; Jest to nadal mocno napisana tablica ciągów.
Nick VanderPyle
1
Nieobsługiwany wyjątek: System.IndexOutOfRangeException: Indeks znajdował się poza obszarem odbicia tablicy. at ArrayClass.Main (Argumenty String []). I wobec tego błędu po zmieniłem int [] zmienna = new int [] {}
yogesh
6
@yogesh: To dziwne. Na przykład podczas pisania int[] variable = new int[]{}i używania go na przykład w pętli, takiej jak foreach (var s in variable){ Console.WriteLine(s);}kod, kompiluje się do: int[] args1 = new int[0];i foreach (int num in args1){Console.WriteLine(num);}. Dlatego nie powinno być żadnej różnicy między używaniem new int[0]a tym, new int[]{}że oba są kompilowane do tego samego kodu.
Nie,
1
@GlennGordon Oczywiście, ale to nowość od wersji C # 3.0 (od 2007 roku, z Visual Studio 2008). Ta wersja pozwala również na inny prosty format var, chociaż tylko dla zmiennych lokalnych (nie dla pól). Jednak w C # 2.0 (Visual Studio 2005) i wcześniejszych trzeba było użyć składni tej odpowiedzi (lub string[] a = new string[0];).
Jeppe Stig Nielsen
113

W .NET 4.6 preferowanym sposobem jest użycie nowej metody Array.Empty:

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

Realizacja jest skrótowo, używając jak członkowie statycznych w klasach ogólnych zachowywać w .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];
}

(dla przejrzystości usunięto kod związany z umową)

Zobacz też:

Kobi
źródło
@Cole Johnson - Dzięki za edycję, ale wycofałem ją. Celowo pominąłem te linie: chciałem zacytować tylko interesujące wdrożenie. Kontrakt kodu i atrybuty przeszkadzają w zrozumieniu tego, co się dzieje (oczywiście link do źródła zawiera wszystko). Dodałem również nowy wiersz w komentarzu, aby uniknąć przewijania w stosie przepełnienia. Jeśli nie masz nic przeciwko, wolę to w ten sposób. Dzięki!
Kobi
2
Zdecydowanie poprawa czytelności z:Enumerable.Empty<T>().ToArray()
DanielV
Mimo że ta metoda jest zdecydowanie preferowana w większości przypadków, nie odpowiada na pierwotne pytanie. OP chce stworzyć pustą tablicę. Array.Empty<T>()czy nie utworzyć tablicę. Zwraca referencję do wstępnie przydzielonej tablicy.
l33t
33

Możesz zainicjować go z rozmiarem 0, ale będziesz musiał go ponownie zainicjować, gdy wiesz, jaki jest rozmiar, ponieważ nie możesz dołączyć go do tablicy.

string[] a = new string[0];
MatthiasG
źródło
To jest dokładna odpowiedź
abzarak,
7

Deklarowanie tablicy bez rozmiaru nie ma większego sensu. Tablica jest o rozmiarze . Deklarując tablicę o określonym rozmiarze, określasz stałą liczbę dostępnych w zbiorze miejsc, które mogą pomieścić różne rzeczy, i odpowiednio przydzielana jest pamięć. Aby coś do niego dodać, musisz zresetować istniejącą tablicę (nawet jeśli zmieniasz rozmiar tablicy, zobacz ten wątek ). Jednym z rzadkich przypadków, w których chcesz zainicjować pustą tablicę, jest przekazanie tablicy jako argumentu.

Jeśli chcesz zdefiniować kolekcję, gdy nie wiesz, jaki to może być rozmiar, tablica nie jest Twoim wyborem, ale czymś podobnym List<T>lub podobnym.

To powiedziawszy, jedynym sposobem zadeklarowania tablicy bez określania rozmiaru jest pusta tablica o rozmiarze 0 . hemant i Alex Dn zapewniają dwa sposoby. Inną prostszą alternatywą jest po prostu :

string[] a = { };

[ Elementy wewnątrz nawiasu powinny być domyślnie konwertowane na zdefiniowany typ, na przykładstring[] a = { "a", "b" }; ]

Lub jeszcze jedno:

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

Oto bardziej deklaratywny sposób :

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

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

Teraz możesz zadzwonić:

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

//or

var a = Array<string>.Empty(5);
nawfal
źródło
1
Nie mogę wymyślić żadnego zastosowania, z wyjątkiem sytuacji, gdy musisz przekazać tablicę jako parametr. W refleksji jest kilka przypadków, w których metoda akceptuje tablicę obiektów i może być konieczne przekazanie pustej tablicy w celu wykonania domyślnej akcji. Zmienię swoją odpowiedź.
nawfal
Na przykład masz interfejs zaimplementowany przez kilka klas zwracających IEnumerable, a jedna z implementacji nie ma elementów dla metody i zwraca na przykład pustą tablicę.
Ignacio Soler Garcia
@IgnacioSolerGarcia Zwróciłbym tablicę w takim przypadku wtedy i tylko wtedy, gdy jest to wyjątkowo krytyczna aplikacja. Powiem, że tablice są nieaktualne i należy tego unikać, jeśli możesz. Zobacz to przez Lipperta i to SO pytanie
nawfal
Pamiętaj, że zwracany typ jest IEnumerable, więc tablica jest tylko do odczytu i nie jest przeznaczona do zmiany. Dlaczego miałbym na przykład zwracać listę w tym przypadku?
Ignacio Soler Garcia
1
Przypadek użycia pustej tablicy jest prosty - jeśli chcesz wypełnić ją obiektami i nie wiesz, ile dodasz!
vapcguy
6

Prosty i elegancki!

string[] array = {}
disklosr
źródło
Zmieniłbym arrayna just a, ponieważ arrayjest to słowo kluczowe przy pisaniu wielkimi literami. Po prostu zła praktyka używania nazwy słowa kluczowego jako nazwy zmiennej - nawet jeśli wielkość liter jest inna. I w zasadzie taka sama jak moja odpowiedź, tyle że ja String.Emptytam miałem .
vapcguy
1
1. tablica nie jest słowem kluczowym ac #. Tablica to klasa, a nie słowo kluczowe 2. „a” to także zła praktyka (może nawet gorsza zła praktyka niż używanie słów kluczowych)
disklosr
Będąc technicznym. Klasa, słowo kluczowe, określa typ obiektu i nadal jest złe. Jak myślisz, dlaczego ajest źle?
vapcguy
1
Ponieważ nieopisowe i jednoliterowe nazwy zmiennych są złą praktyką, ponieważ nie przekazują powodu ich definiowania. „tablica” jest z pewnością lepszą nazwą niż „a”. Lepszą nazwą byłoby „emptyArray”.
disklosr
4

string[] a = new string[0];

lub krótki zapis:

string[] a = { };

Preferowanym sposobem jest teraz:

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

Napisałem krótkie wyrażenie regularne, którego możesz użyć w Visual Studio, jeśli chcesz zastąpić przydziały zerowej długości, np new string[0]. Użyj Znajdź (wyszukaj) w Visual Studio z włączoną opcją Wyrażenie regularne:

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

Teraz Znajdź wszystko lub F3 (Znajdź następny) i zamień wszystko na Array.Empty <…> ()!

juFo
źródło
3

Możesz zdefiniować rozmiar tablicy w czasie wykonywania .

Pozwoli ci to zrobić cokolwiek, aby dynamicznie obliczyć rozmiar tablicy. Ale raz zdefiniowany rozmiar jest niezmienny.

Array a = Array.CreateInstance(typeof(string), 5);
radarbob
źródło
4
Dlaczego to wszystko? W czasie wykonywania można normalnie zdefiniować rozmiar tablicy na podstawie zmiennej:int i = 5; string[] a = new string[i];
Kevin Brock
Cóż, wydaje mi się, że w przypadku leków generycznych jest to przestarzałe.
radarbob
2

Próbowałem:

string[] sample = new string[0];

Ale mogłem wstawić tylko jeden ciąg, a następnie wystąpił błąd wyjątku OutOfBound, więc po prostu ustawiłem dla niego rozmiar, na przykład

string[] sample = new string[100];

Lub inny sposób, który działa dla mnie:

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

Przypisywanie wartości do listy:

sample.Add(your input);
Cs_Lu
źródło
1

Jak wiem, nie możesz zrobić tablicy bez rozmiaru, ale możesz użyć

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

i potem l.ToArray().

Alex Dn
źródło
1

Łącząc sugestie @nawfal i @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];
    }
}

Przykład użycia:

Array<string>.Empty

AKTUALIZACJA 14.05.2019

(podziękowania dla @Jaider ty)

Lepsze wykorzystanie .Net API:

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

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

Dotyczy:

.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

...

HTH

ShloEmi
źródło
1
W .NET Core 2 jest już rozszerzenie,arr = Array.Empty<string>();
Jaider
iirc, w .NetStandart [4. coś] - jest też.
ShloEmi
0

Możesz to zrobić:

string[] a = { String.Empty };

Uwaga: OP oznaczało, że nie trzeba określać rozmiaru, a tablica nie ma rozmiarów

vapcguy
źródło
7
Czy to nie stworzy tablicy ciągów o długości 1?
Sumner Evans
To prawda, ale jest wyczyszczone. I OP poprosił o zadeklarowanie tablicy bez konieczności określania rozmiaru - to pasuje do tego.
vapcguy
A to zasługuje na opinię, dlaczego? OP oznaczało brak konieczności zmiany specifyrozmiaru, nie tworzenie tablicy sizeless.
vapcguy
1
@vapcguy Byłem downvoter. Żałuję tego. Zredagowałem twoją odpowiedź, aby anulować moją opinię. Twój komentarz sprawia, że ​​pytanie jest nieco wątpliwe. Nie jestem pewien, czy to właśnie oznaczało OP.
nawfal
4
OP poprosił o pustą tablicę. Ta tablica nie jest pusta.
Keith,
0

Oto przykład ze świata rzeczywistego. W tym celu konieczne jest zainicjowanie tablicy foundFilesnajpierw do zera długości.

(Jak podkreślono w innych odpowiedziach: To nie inicjuje elementu, a zwłaszcza elementu o indeksie zero, ponieważ oznaczałoby to, że tablica ma długość 1. Tablica ma zerową długość po tej linii!).

Jeśli część = string[0]zostanie pominięta, wystąpi błąd kompilatora!

Wynika to z blokady zaczepu bez ponownego rzucania. Kompilator C # rozpoznaje ścieżkę kodu, że funkcja Directory.GetFiles()może zgłosić wyjątek, aby tablica mogła zostać niezainicjowana.

Zanim ktokolwiek powie, brak ponownego zgłoszenia wyjątku byłby złym sposobem obsługi błędów: To nie jest prawda. Obsługa błędów musi spełniać wymagania.

W takim przypadku zakłada się, że program powinien kontynuować w przypadku katalogu, którego nie można odczytać, a nie złamać - najlepszym przykładem jest funkcja przechodząca przez strukturę katalogów. Tutaj obsługa błędów polega tylko na logowaniu. Oczywiście można to zrobić lepiej, np. Zbierając wszystkie katalogi z nieudanymi GetFiles(Dir)połączeniami na liście, ale doprowadzi to zbyt daleko tutaj.

Wystarczy stwierdzić, że unikanie throwjest prawidłowym scenariuszem, więc tablica musi zostać zainicjowana do długości zero. Wystarczyłoby to zrobić w bloku catch, ale byłby to zły styl.

Wywołanie zmiany GetFiles(Dir)rozmiaru tablicy.

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
źródło