web-dev-qa-db-fra.com

Classe statique C # vs struct pour des chaînes prédéfinies

Un collègue vient de créer la construction suivante en C # (l'exemple de code est simplifié). Son objectif était de raccourcir la notation de toutes les chaînes prédéfinies dans le reste du code.

public struct PredefinedStrings
{
    public const string VeryLongName = "Very Long Name";
    public const string AnotherVeryLongName = "Another Very Long Name";
    public const string TheLastVeryLongName = "The Last Very Long Name";
}

public static void MethodThatUsesTheNames()
{
    Console.WriteLine(PredefinedStrings.VeryLongName);
    Console.WriteLine(PredefinedStrings.AnotherVeryLongName);
    Console.WriteLine(PredefinedStrings.TheLastVeryLongName);
}

Bien que cela semble fonctionner correctement pour lui, je ne peux pas m'empêcher de me demander s'il aurait dû utiliser une classe statique au lieu d'une structure ou s'il existe un moyen plus élégant d'y parvenir.

Quel serait le moyen préféré de faire cela? S'il vous plaît également expliquer pourquoi.

42
Rob van Groenewoud

Avec la solution struct, rien ne peut empêcher un autre code de faire new PredefinedStrings(), ce qui ne fera pas rien de mal , mais c'est quelque chose qu'il est sémantiquement difficile à autoriser. Avec une classe statique, le compilateur vous interdira la création. Et il va sans dire que la classe statique est le moyen privilégié de fournir des constantes dans Framework.

edit pour ajouter, j’ai dit cette deuxième partie sans preuve - j’ai depuis fait une recherche et trouvé assez rapidement System.Net.Mime.DispositionTypeNames et System.Net.WebRequestMethods.Http.

41
AakashM

Je préférerais que les chaînes soient toutes dans un fichier de ressources et non incorporées dans le code - principalement pour des raisons d'internationalisation. On peut y accéder via une classe statique avec les valeurs en tant que membres de propriété.

30
Andrew

Outre un static class et struct, pourquoi ne pas envisager d'utiliser des fichiers resource pour les chaînes constantes? Celles-ci sont facilement accessibles en tant que SomeNamespace.ResourceName.KeyName et, en fonction de leur emplacement dans votre projet, peuvent être gérées en externe sans être recompilées si nécessaire.

25
KP.

Règle simple: n'utilisez jamais de structure tant que vous n'avez pas d'autre choix.

Les constantes ont quelques inconvénients:

  • seuls des types simples peuvent être utilisés (chaînes, chiffres, etc.)
  • les constantes sont injectées dans les assemblages de référence. Si vous recompilez un assemblage avec des constantes et que vous ne le recompilez pas, vous aurez des problèmes

J'écrirais votre code comme ceci (notez également le refactoring de renommage):

public static class KnownNames
{
    public static readonly string VeryLong = "Very Long Name";
    public static readonly string AnotherVeryLong = "Another Very Long Name";
    public static readonly string TheLastVeryLong = "The Last Very Long Name";
}
9
Konstantin Spirin

On dirait que vous cherchez un fichier de ressources (.resx). C'est un endroit convenable pour stocker de telles chaînes, et résumer vos chaînes dans un fichier .resx facilitera la localisation future de votre application. La page MSDN sur http://msdn.Microsoft.com/en-us/library/1ztca10y.aspx est un bon début pour plus d’informations.

6
stack

Il n'y a rien de mal fonctionnellement avec ce code. Mais stylistiquement, je suis d'accord pour dire qu'une classe statique est préférable. Une classe statique déclare que l'intention du type est de ne contenir que des données statiques/constantes. 

5
JaredPar

N'oubliez pas la recommandation selon laquelle une taille de structure devrait être d'environ 16 octets. Dans un système 32 bits, il s'agit de 4 références System.String. Je dirais que vous êtes mieux avec une classe statique si le nombre de chaînes va augmenter.

5
Jesse C. Slicer

Les structures sont normalement évitées sauf si elles répondent à certains critères tels que détaillés dans cette réponse .

Puisque votre collègue ne l'utilise pas pour stocker une valeur, il devrait utiliser une classe, pas une structure.

1
Trisped

la classe statique semble être la meilleure voie à suivre car elle est la plus standard et la plus attendue. Je pensais que les versions de struct/const pourraient être plus rapides mais après quelques tests, elles ne l’étaient pas.

Voici les résultats de mon test rapide comprenant longueur, comparaison, concat, copie, indexOf et sous-chaîne. Il a été exécuté sous .Net 4.0 dans la version sans un débogueur attaché.

                                          .Net 3.0  .Net 4.0
static class with static read-only string:  0.217   0.364  seconds
static class with const            string:  0.211   0.361  seconds
struct       with static read-only string:  0.211   0.372  seconds
struct       with const            string:  0.214   0.371  seconds
Properties.Resources               string:  1.173   1.268  seconds

Toutes les performances étaient identiques, sauf lorsque vous utilisez un fichier de ressources, ce qui est plus lent. Bien que Properties.Resources soit plus lent, il n'est pas stocké dans l'exécutable, ce qui peut être plus approprié dans certains cas. Donc, utilisez "classe statique" ou Propriétés.Resources stockant des chaînes à mon avis.

1
Sunsetquest

Je pense que statique est mieux et voici mon raisonnement. Si ce code réside dans une bibliothèque et qu'un autre élément de code consomme cette bibliothèque, si la valeur des champs constants change, alors non seulement cette bibliothèque devra être recompilée (duh), mais vous devrez recompiler le code qui utilise cette bibliothèque aussi. La raison en est que la compilation insère les valeurs constantes partout où vous les référencez. Si vous utilisez cependant statique, vous ne rencontrerez pas ce problème, car vous référencez le champ pas le valeur .

1
BFree

Dans ma pratique à cette fin, nous utilisons Dictionary<enumNameType, string>. Où enumNameType correspond aux différents types de noms que vous pouvez avoir (dans votre cas) ... Ce dictionnaire est encapsulé dans une classe statique et est mis en cache - nous le créons juste la première fois que nous l'utilisons, puis nous retournons le même objet ...

J'espère que cela vous sera utile aussi!

0
anthares

J'utilise aussi des structures pour les constantes, mais uniquement pour un usage interne, pas pour les API publiques. Cela semble naturel puisque les enums sont également convertis en structures.

0
Max Toro

Le simple fait que vous soyez autorisé à créer un nouvel objet qui se veut constant est une preuve évidente d'une mauvaise pratique (généralement). Je dis «généralement» parce que .NET utilise ce concept de temps en temps, sans que l'on sache pourquoi.

Bien sûr, vous pouvez toujours faire des choses comme ça:

public class Foo
{
    public struct Bar
    {
        public static double A = 100;

        public Bar(double a)
        {
            A = a;
        }
    }
}

Ce qui justifie techniquement la création de Bar; cependant, rien ne garantit que la constante Bar sera toujours la même (même dans un environnement à un seul thread) et est finalement peu utile.

0
James M