Comment initialiser un tableau vide en C #?

328

Est-il possible de créer un tableau vide sans spécifier la taille?

Par exemple, j'ai créé:

String[] a = new String[5];

Pouvons-nous créer le tableau de chaînes ci-dessus sans la taille?

yogesh
la source
2
stackoverflow.com/questions/151936/… u vérifiez ce lien, il peut vous aider à comprendre clairement les éléments du tableau
Ravi Gadag

Réponses:

436

Si vous allez utiliser une collection dont vous ne connaissez pas la taille à l'avance, il existe de meilleures options que les tableaux.

Utilisez List<string>plutôt un - il vous permettra d'ajouter autant d'éléments que nécessaire et si vous avez besoin de retourner un tableau, appelez ToArray()la variable.

var listOfStrings = new List<string>();

// do stuff...

string[] arrayOfStrings = listOfStrings.ToArray();

Si vous devez créer un tableau vide, vous pouvez le faire:

string[] emptyStringArray = new string[0]; 
Oded
la source
1
@Oded - chaîne [] emptyStringArray = nouvelle chaîne [0]; ne donne pas lieu à un tableau vide, n'est-ce pas? Il semble que ce soit un tableau avec un élément où cet élément est nul.
rory.ap
11
@roryap - Non. Il en résulte un string[]qui n'a aucun élément. Si vous essayez d'accéder emptyStringArray[0], vous obtiendrez unIndexOutOfRangeException
Oded
@Oded - Merci, je suis relativement nouveau sur C #. Dans VB, l'index fourni est la limite supérieure, pas le nombre d'éléments.
rory.ap
1
Que considéreriez-vous mieux: var strings = new string [] {}; ou var strings = new string [0]; BTW: Je considère un tableau vide par défaut parfaitement valide pour les paramètres de méthode: public void EditItems (IEnumerable <Item> toEdit, IEnumerable <long> toDelete = new long [] {})
realbart
6
@ RickO'Shea - C ++ n'est pas C #. Stroustrup connaît son C ++ - pas si sûr qu'il connaisse son C # et le GC .NET. Je ne vais pas entrer en guerre religieuse avec toi.
Odé le
182

Essaye ça:

string[] a = new string[] { };
hémant
la source
7
En développant cette réponse, vous pouvez également initier le tableau avec des éléments sans spécifier la taille OU le type, le compilateur déduira soit de l'initialiseur: var a = new [] {"a", "b", "c"}; Il s'agit toujours d'un tableau de chaînes fortement typé.
Nick VanderPyle
1
Exception non gérée: System.IndexOutOfRangeException: l'index était en dehors des rebonds du tableau. à ArrayClass.Main (String [] args). J'ai rencontré cette erreur après avoir changé mon int [] variable = new int [] {}
yogesh
6
@yogesh: C'est étrange. Quand par exemple l'écrire int[] variable = new int[]{}et l'utiliser par exemple dans une boucle telle que foreach (var s in variable){ Console.WriteLine(s);}le code est compilé en: int[] args1 = new int[0];et foreach (int num in args1){Console.WriteLine(num);}. Il ne devrait donc pas y avoir de différence entre l'utilisation de new int[0]et new int[]{}car les deux sont compilés dans le même code.
Non
1
@GlennGordon Absolument, mais c'est nouveau depuis la version C # 3.0 (à partir de 2007, avec Visual Studio 2008). Cette version permet également un autre format simple avec var, mais uniquement pour les variables locales (pas pour les champs). Cependant, en C # 2.0 (Visual Studio 2005) et versions antérieures, vous deviez utiliser la syntaxe de cette réponse (ou string[] a = new string[0];).
Jeppe Stig Nielsen
114

Dans .NET 4.6, la méthode préférée consiste à utiliser une nouvelle méthode Array.Empty:

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

L' implémentation est succincte, en utilisant comment les membres statiques dans les classes génériques se comportent dans .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];
}

(code lié au contrat de code supprimé pour plus de clarté)

Voir également:

Kobi
la source
@Cole Johnson - Merci pour la modification, mais je l'ai annulée. J'ai omis ces lignes exprès: je voulais juste citer l'implémentation intéressante. Le contrat de code et les attributs empêchent simplement de comprendre ce qui se passe (le lien vers la source a tout, bien sûr). J'ai également ajouté une nouvelle ligne dans le commentaire pour éviter de faire défiler Stack Overflow. Si cela ne vous dérange pas, je le préfère de cette façon. Merci!
Kobi
2
Certainement une amélioration de la lisibilité de:Enumerable.Empty<T>().ToArray()
DanielV
Même si cette méthode est définitivement préférée dans la plupart des cas, elle ne répond pas à la question d'origine. L'OP veut créer un tableau vide. Array.Empty<T>()ne crée pas de tableau. Il renvoie une référence à un tableau pré-alloué.
l33t
33

Vous pouvez l'initialiser avec une taille de 0, mais vous devrez la réinitialiser lorsque vous saurez quelle est la taille, car vous ne pourrez pas l'ajouter au tableau.

string[] a = new string[0];
MatthiasG
la source
C'est la réponse exacte
abzarak
7

Il ne sert à rien de déclarer un tableau sans taille. Un tableau est de taille environ . Lorsque vous déclarez un tableau de taille spécifique, vous spécifiez le nombre fixe d'emplacements disponibles dans une collection pouvant contenir des éléments, et en conséquence la mémoire est allouée. Pour y ajouter quelque chose, vous devrez de toute façon réinitialiser le tableau existant (même si vous redimensionnez le tableau, consultez ce fil ). L'un des rares cas où vous voudriez initialiser un tableau vide serait de passer le tableau en argument.

Si vous souhaitez définir une collection lorsque vous ne savez pas de quelle taille elle pourrait être, le tableau n'est pas votre choix, mais quelque chose comme un List<T> ou similaire.

Cela dit, la seule façon de déclarer un tableau sans spécifier de taille est d'avoir un tableau vide de taille 0 . hemant et Alex Dn proposent deux méthodes. Une autre alternative plus simple consiste à :

string[] a = { };

[ Les éléments à l'intérieur du support doivent être implicitement convertibles en type défini, par exemple,string[] a = { "a", "b" }; ]

Ou encore un autre:

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

Voici une manière plus déclarative :

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

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

Vous pouvez maintenant appeler:

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

//or

var a = Array<string>.Empty(5);
nawfal
la source
1
Je ne peux penser à aucune utilisation, sauf lorsque vous devez passer un tableau en tant que paramètre. Il existe quelques cas de réflexion dans lesquels une méthode accepte un tableau d'objets et vous souhaiterez peut-être passer un tableau vide pour effectuer l'action par défaut. Je vais modifier ma réponse.
nawfal
Vous avez par exemple une interface implémentée par plusieurs classes retournant un IEnumerable et l'une des implémentations n'a pas d'éléments pour la méthode et retourne un tableau vide par exemple.
Ignacio Soler Garcia
@IgnacioSolerGarcia Je retournerais un tableau dans ce cas si et seulement s'il s'agissait d'une application extrêmement critique en termes de performances. Je dirai que les tableaux sont obsolètes et doivent être évités si vous le pouvez. Voir ceci par Lippert et cette question SO
nawfal
Gardez à l'esprit que le type renvoyé est IEnumerable, donc le tableau est en lecture seule et il n'est pas destiné à changer. Pourquoi devrais-je retourner une liste dans ce cas par exemple?
Ignacio Soler Garcia
1
Un cas d'utilisation pour un tableau vide est simple - lorsque vous voulez le remplir d'objets et que vous ne savez pas combien vous allez en ajouter!
vapcguy
6

Simple et élégant!

string[] array = {}
disklosr
la source
Je changerais arraysimplement a, tout comme arrayun mot-clé une fois capitalisé. Juste une mauvaise pratique pour utiliser un nom de mot clé comme nom de variable - même si le cas est différent. Et fondamentalement la même que ma réponse, sauf que j'avais String.Emptylà-dedans.
vapcguy
1
1. tableau n'est pas un mot clé ac #. Array est une classe et non un mot-clé 2. "a" est aussi une mauvaise pratique (peut-être pire encore une mauvaise pratique que d'utiliser des mots-clés)
disklosr
Être technique. Classe, mot-clé, il définit un type d'objet et est toujours mauvais. Pourquoi pensez-vous que ac'est mauvais?
vapcguy
1
Parce que les noms de variable non descriptifs et à une lettre sont de mauvaises pratiques car ils ne transmettent pas la raison de leur définition. "array" est certainement un meilleur nom que "a". Un meilleur nom serait "emptyArray".
disklosr
4

string[] a = new string[0];

ou notation courte:

string[] a = { };

La voie préférée est maintenant:

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

J'ai écrit une expression régulière courte que vous pouvez utiliser dans Visual Studio si vous souhaitez remplacer des allocations de longueur nulle, par exemple new string[0]. Utilisez la recherche (recherche) dans Visual Studio avec l'option Expression régulière activée:

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

Maintenant, trouvez tout ou F3 (Rechercher suivant) et remplacez tout par Array.Empty <…> ()!

juFo
la source
3

Vous pouvez définir la taille du tableau lors de l'exécution .

Cela vous permettra de faire n'importe quoi pour calculer dynamiquement la taille du tableau. Mais, une fois définie, la taille est immuable.

Array a = Array.CreateInstance(typeof(string), 5);
radarbob
la source
4
Pourquoi faire tout ça? Au moment de l'exécution, vous pouvez définir la taille du tableau à partir d'une variable normalement:int i = 5; string[] a = new string[i];
Kevin Brock
Eh bien, je suppose qu'avec les génériques, cela semble être obsolète.
radarbob
2

J'avais essayé:

string[] sample = new string[0];

Mais je ne pouvais y insérer qu'une chaîne, puis j'ai eu une erreur exceptionOutOfBound, donc j'ai simplement mis une taille pour cela, comme

string[] sample = new string[100];

Ou une autre façon qui fonctionne pour moi:

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

Attribution d'une valeur à la liste:

sample.Add(your input);
Cs_Lu
la source
1

Comme je sais, vous ne pouvez pas créer de tableau sans taille, mais vous pouvez utiliser

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

et puis l.ToArray().

Alex Dn
la source
1

Combiner les suggestions @nawfal et @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];
    }
}

Exemple d'utilisation:

Array<string>.Empty

MISE À JOUR 2019-05-14

(crédits à @Jaider ty)

Meilleure utilisation de l'API .Net:

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

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

S'applique à:

.NET Core: 3.0 Aperçu 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 Aperçu 2.0 1.6 1.5 1.4 1.3

...

HTH

ShloEmi
la source
1
Dans .NET Core 2, il existe déjà une extension pour celui-ci,arr = Array.Empty<string>();
Jaider
iirc, dans .NetStandart [4.quelque chose] - il y en a aussi.
ShloEmi
0

Tu peux faire:

string[] a = { String.Empty };

Remarque: OP signifiait ne pas avoir à spécifier de taille, pas à rendre un tableau sans taille

vapcguy
la source
8
Cela ne créera-t-il pas un tableau de chaînes de longueur 1?
Sumner Evans,
C'est vrai, mais c'est effacé. Et OP a demandé de déclarer le tableau sans avoir à indiquer de taille - cela correspond à cela.
vapcguy
Et cela mérite un downvote, pourquoi? OP signifiait ne pas avoir de specifytaille, pas faire de tableau sizeless.
vapcguy
1
@vapcguy J'étais le downvoter. Je regrette ça. J'ai modifié votre réponse pour annuler mon downvote. Votre commentaire rend la question un peu douteuse. Je ne sais pas si c'est ce que OP voulait dire.
nawfal
4
L'OP a demandé un tableau vide . Ce tableau n'est pas vide.
Keith
0

Voici un exemple du monde réel. En cela, il est nécessaire d'initialiser le tableaufoundFiles abord à une longueur nulle.

(Comme souligné dans d'autres réponses: cela n'initialise pas un élément et surtout pas un élément d'index zéro car cela signifierait que le tableau avait une longueur 1. Le tableau a une longueur nulle après cette ligne!).

Si la partie = string[0]est omise, il y a une erreur de compilation!

C'est à cause du bloc catch sans rethrow. Le compilateur C # reconnaît le chemin de code, que la fonction Directory.GetFiles()peut lever une exception, afin que le tableau puisse être non initialisé.

Avant que quelqu'un ne le dise, ne pas lever l'exception serait une mauvaise gestion des erreurs: ce n'est pas vrai. La gestion des erreurs doit répondre aux exigences.

Dans ce cas, il est supposé que le programme doit continuer dans le cas d'un répertoire qui ne peut pas être lu, et ne pas casser - le meilleur exemple est une fonction traversant une structure de répertoire. Ici, la gestion des erreurs consiste simplement à l'enregistrer. Bien sûr, cela pourrait être mieux fait, par exemple en collectant tous les répertoiresGetFiles(Dir) appels dans une liste, mais cela mènera trop loin ici.

Il suffit d'indiquer que l'évitement throwest un scénario valide, et donc le tableau doit être initialisé à la longueur zéro. Il suffirait de le faire dans le bloc catch, mais ce serait un mauvais style.

L'appel à GetFiles(Dir)redimensionner le tableau.

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
la source