web-dev-qa-db-fra.com

Déclarer un tableau const

Est-il possible d'écrire quelque chose de similaire au suivant?

public const string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
407
Jaime Oro

Oui, mais vous devez le déclarer readonly au lieu de const:

public static readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

La raison en est que const ne peut être appliqué qu'à un champ dont la valeur est connue au moment de la compilation. L'initialiseur de tableau que vous avez montré n'est pas une expression constante en C #, il génère donc une erreur du compilateur.

La déclarer readonly résout ce problème car la valeur n'est initialisée qu'à l'exécution (bien qu'il soit garanti qu'elle ait été initialisée avant la première utilisation du tableau).

En fonction de ce que vous souhaitez réaliser, vous pouvez également envisager de déclarer une énumération:

public enum Titles { German, Spanish, Corrects, Wrongs };
623
Cody Gray

Vous pouvez déclarer un tableau en tant que readonly, mais n'oubliez pas que vous pouvez changer l'élément de readonly tableau.

public readonly string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };
...
Titles[0] = "bla";

Pensez à utiliser enum, comme suggéré par Cody, ou IList.

public readonly IList<string> ITitles = new List<string> {"German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();
53
Branimir

Vous ne pouvez pas créer de tableau 'const' car les tableaux sont des objets et ne peuvent être créés qu'au moment de l'exécution et les entités const sont résolues au moment de la compilation.

Ce que vous pouvez faire à la place est de déclarer votre tableau comme "en lecture seule". Cela a le même effet que const, sauf que la valeur peut être définie au moment de l'exécution. Il ne peut être défini qu’une fois, puis il s’agit d’une valeur en lecture seule (c’est-à-dire const).

44
JAiro

Depuis le n ° 6, vous pouvez l'écrire comme ceci:

public static string[] Titles => new string[] { "German", "Spanish", "Corrects", "Wrongs" };

Voir aussi: C #: Le C 6.0 nouveau et amélioré (plus précisément le chapitre "Propriétés et propriétés associées à l'expression")

Cela créera une propriété statique en lecture seule, mais vous permettra quand même de modifier le contenu du tableau renvoyé, mais lorsque vous appelez à nouveau la propriété, vous obtenez à nouveau le tableau d'origine non modifié.

Pour clarifier, ce code est le même que (ou en réalité un raccourci pour):

public static string[] Titles
{
    get { return new string[] { "German", "Spanish", "Corrects", "Wrongs" }; }
}

Veuillez noter que cette approche présente des inconvénients: Un nouveau tableau est en fait instancié sur chaque référence. Par conséquent, si vous utilisez un très grand tableau, cela risque de ne pas être la solution la plus efficace. Mais si vous réutilisez le même tableau (en le plaçant par exemple dans un attribut privé), vous aurez de nouveau la possibilité de changer le contenu du tableau.

Si vous voulez avoir un tableau immuable (ou une liste), vous pouvez aussi utiliser:

public static IReadOnlyList<string> Titles { get; } = new string[] { "German", "Spanish", "Corrects", "Wrongs" };

Cependant, cela comporte toujours un risque de modification, car vous pouvez toujours le reconvertir en chaîne [] et modifier le contenu, en tant que tel:

((string[]) Titles)[1] = "French";
11
mjepson

Vous pouvez adopter une approche différente: définissez une chaîne constante pour représenter votre tableau, puis divisez-la en un tableau lorsque vous en avez besoin, par exemple.

const string DefaultDistances = "5,10,15,20,25,30,40,50";
public static readonly string[] distances = DefaultDistances.Split(',');

Cette approche vous donne une constante qui peut être stockée dans la configuration et convertie en tableau si nécessaire.

Alastair

6
Alastair

Si vous déclarez un tableau derrière une interface IReadOnlyList, vous obtenez un tableau constant avec des valeurs constantes déclaré à l'exécution:

public readonly IReadOnlyList<string> Titles = new [] {"German", "Spanish", "Corrects", "Wrongs" };

Disponible dans .NET 4.5 et supérieur.

6
Richard Garside

A . NET Framework v4.5 + solution qui améliore la version réponse de tdbeckett :

_using System.Collections.ObjectModel;

// ...

public ReadOnlyCollection<string> Titles { get; } = new ReadOnlyCollection<string>(
  new string[] { "German", "Spanish", "Corrects", "Wrongs" }
);
_

Remarque: étant donné que la collection est conceptuellement constante, il peut être judicieux de définir static pour la déclarer au niveau de la classe .

Ce qui précède:

  • Initialise le champ de sauvegarde implicite de la propriété une fois avec le tableau.

    • Notez que _{ get; }_ - c’est-à-dire ne déclarer qu’une propriété getter - est ce qui rend la propriété elle-même implicitement en lecture seule (en essayant de combiner readonly avec _{ get; }_ est en fait une erreur de syntaxe).

    • Sinon, vous pouvez simplement omettre le _{ get; }_ et ajouter readonly pour créer un champ à la place d'une propriété, comme dans la question, mais en exposant public données membres en tant que propriétés plutôt que des champs est une bonne habitude à former.

  • Crée un tableau - semblable à (permettant un accès indexé ) c'est-à-dire réellement et robustement en lecture seule (conceptuellement constant, une fois créé), les deux en ce qui concerne:

    • empêchant la modification de la collection dans son ensemble (par exemple en supprimant ou en ajoutant des éléments, ou en affectant une nouvelle collection à la variable).
    • empêchant la modification de éléments individuels .
      (Même une modification indirecte n’est pas possible - contrairement à un IReadOnlyList<T> solution, où un _(string[])_ cast peut être utilisé pour obtenir un accès en écriture aux éléments , comme indiqué dans tile de mjepsen réponse .
      La même vulnérabilité s’applique à l'interface _IReadOnlyCollection<T>_ , qui, malgré la similitude de nom avec , la classe ReadOnlyCollection, ne supporte même pas indexée access , ce qui le rend fondamentalement inapproprié pour fournir un accès semblable à un tableau.)
5
mklement0

Pour mes besoins, je définis static tableau, au lieu de impossible const et cela fonctionne: public static string[] Titles = { "German", "Spanish", "Corrects", "Wrongs" };

5
ALZ

C'est une façon de faire ce que tu veux:

using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;

public ReadOnlyCollection<string> Titles { get { return new List<string> { "German", "Spanish", "Corrects", "Wrongs" }.AsReadOnly();}}

Cela ressemble beaucoup à faire un tableau en lecture seule.

3
tdbeckett

Par souci d’exhaustivité, nous disposons maintenant également de ImmutableArrays. Cela devrait être vraiment immuable:

public readonly static ImmutableArray<string> Tiles = ImmutableArray.Create(new[] { "German", "Spanish", "Corrects", "Wrongs" });

Requiert une référence System.Collections.Immutable NuGet

https://msdn.Microsoft.com/en-us/library/mt452182 (v = vs.111) .aspx

2
shurik

Je crois que vous ne pouvez le faire qu'en lecture seule.

2
skaz

Les tableaux sont probablement l'une de ces choses qui ne peuvent être évaluées qu'au moment de l'exécution. Les constantes doivent être évaluées au moment de la compilation. Essayez d'utiliser "readonly" au lieu de "const".

1
nemke

Au lieu de cela, pour contourner le problème elements-can-be-be-modified avec un tableau en lecture seule, vous pouvez utiliser une propriété statique à la place. (Les éléments individuels peuvent toujours être modifiés, mais ces modifications ne seront effectuées que sur la copie locale du tableau.)

public static string[] Titles 
{
    get
    {
        return new string[] { "German", "Spanish", "Corrects", "Wrongs"};
    }
}

Bien sûr, cela ne sera pas particulièrement efficace car un nouveau tableau de chaînes est créé à chaque fois.

0
Hutch