Statique en lecture seule vs const

1387

J'ai lu environ constet static readonlychamps. Nous avons certaines classes qui ne contiennent que des valeurs constantes. Utilisé pour diverses choses dans notre système. Je me demande donc si mon observation est correcte:

Ce type de valeurs constantes devrait-il toujours s'appliquer static readonlyà tout ce qui est public? Et utiliser uniquement constpour les valeurs internes / protégées / privées?

Que recommandez-vous? Dois-je peut-être même ne pas utiliser de static readonlychamps, mais plutôt utiliser des propriétés?

Svish
la source
5
Voici un cas unique très intéressant que je viens de trouver en faveur de static readonly: essayez d'utiliser un const à l'intérieur d'un IEnumeratorqui déclencherait une irrécupérable yield et vous obtiendrez une "erreur de compilation interne" redoutée . Je n'ai pas testé le code en dehors d'Unity3D, mais j'espère qu'il s'agit d'un bug mono ou .NET . C'est néanmoins un problème c # .
cregox
8
une autre différence est que vous pouvez utiliser une chaîne const dans un commutateur, mais pas une chaîne statique en lecture seule
flagg19
7
static readonlyne peut pas être utilisé dans l' switch-caseinstruction comme casevariable, constest requis à cet effet.
Mostafiz Rahman
3
static readonlyne peut pas être utilisé aussi comme paramètre d'attribut
Dread Boy

Réponses:

940

public static readonlyles champs sont un peu inhabituels; public staticles propriétés (avec seulement un get) seraient plus courantes (peut-être soutenues par un private static readonlychamp).

constles valeurs sont gravées directement dans le site d'appel; c'est à double tranchant:

  • il est inutile si la valeur est récupérée au moment de l'exécution, peut-être depuis config
  • si vous changez la valeur d'un const, vous devez reconstruire tous les clients
  • mais cela peut être plus rapide, car cela évite un appel de méthode ...
  • ... qui aurait parfois pu être souligné par le JIT de toute façon

Si la valeur ne changera jamais , alors const est bien - Zeroetc faire des consts raisonnables; p En dehors de cela, les staticpropriétés sont plus courantes.

Marc Gravell
la source
13
Pourquoi une propriété sur un terrain? Si c'est une classe immuable, je ne vois aucune différence.
Michael Hedgpeth
73
@Michael - mêmes raisons que toujours; il masque l'implémentation. Vous pouvez trouver (plus tard) que vous devez être chargé paresseusement, basé sur la configuration, une façade ou autre. En réalité, l'un ou l'autre irait souvent bien ...
Marc Gravell
42
@CoffeeAddict par définition, une constante ne tire pas de valeurs d'un fichier de configuration; il est gravé en tant que littéral au moment de la compilation. La seule façon d'utiliser une constante au moment de l'exécution est de réfléchir sur les champs. Chaque fois que vous essayez de l'utiliser, le compilateur remplace déjà votre utilisation constante par une utilisation littérale ; c'est-à-dire que si une méthode dans votre code utilise 6 constantes, et que vous l'inspectez comme IL, il n'y aura aucune mention de recherches constantes; les valeurs littérales seront simplement chargées in situ
Marc Gravell
37
@MarcGravell - ATTENTION: les readonlychamps ne peuvent pas être utilisés dans les instructions switch / case, mais vous en avez besoin const.
Luciano
7
@didibus La modification d'un champ en une propriété rompt en fait l'API. Un champ en C # agit efficacement comme une variable, tandis qu'une propriété en C # est une aide syntaxique pour écrire une méthode getter et / ou une méthode setter. Cette différence est importante lorsque d'autres assemblages sont impliqués. Si vous modifiez un champ en propriété et que d'autres assemblys dépendent de ce champ, ces autres assemblys doivent être recompilés.
Stephen Booher
237

J'utiliserais static readonlysi le consommateur est dans un assemblage différent. Avoir le constet le consommateur dans deux assemblages différents est une bonne façon de se tirer une balle dans le pied .

Michael Stum
la source
5
Donc, je pense que comme certains l'ont mentionné ou fait allusion, il peut être judicieux d'utiliser uniquement const pour les valeurs qui sont en fait des constantes bien connues si elles sont rendues publiques, sinon elles devraient être réservées pour la portée d'accès interne, protégée ou privée.
jpierson
1
@Dio La raison pour laquelle il existe toujours est parce que ce n'est pas un problème en soi - c'est quelque chose dont il faut être conscient, mais la possibilité d'inclure des consts au-delà des limites de l'assemblage est une bonne chose pour les performances. C'est vraiment juste une question de vraiment comprendre que «constant» signifie «ça ne changera jamais».
Michael Stum
1
@MichaelStum Ok je ne devrais pas appeler ça "un problème". Dans ma ligne de travail, j'ai const et le partage entre les assemblys mais je recompile pour chaque déploiement ou envoi de code. Néanmoins, ce fait mérite certainement d'être pris en compte.
Dio Phung
1
Donc, en général, internal constou en public static readonlyfonction de la visibilité souhaitée.
Iiridayn
2
@Iiridayn Ouais, ce n'est pas une mauvaise façon de voir les choses. Il y a quelques cas limites à considérer (par exemple, si vous utilisez Reflection, ou si une valeur est requise sur un attribut), et il existe des utilisations valides pour public const(par exemple, tout ce qui fait partie d'une norme. Chaque fois que je travaille avec XML, il y a un fichier d'espaces de noms avec un tas de public const string.) Mais en général, public constne doit être utilisé qu'après avoir considéré les implications correctement.
Michael Stum
200

Peu de choses plus pertinentes à noter:

const int a

  • doit être initialisé.
  • l'initialisation doit être au moment de la compilation .

en lecture seule dans un

  • peut utiliser une valeur par défaut, sans initialisation.
  • l'initialisation peut être effectuée au moment de l'exécution (Edit: dans le constructeur uniquement).
Peter
la source
39
dans le ctorseul.
Amit Kumar Ghosh
1
Non seulement dans le constructeur mais aussi dans la déclaration ( docs.microsoft.com/en-us/dotnet/csharp/language-reference/… ).
deChristo
176

Ceci n'est qu'un complément aux autres réponses. Je ne les répéterai pas (maintenant quatre ans plus tard).

Il y a des situations où a constet un non-const ont une sémantique différente. Par exemple:

const int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

s'imprime Truealors que:

static readonly int y = 42;

static void Main()
{
  short x = 42;
  Console.WriteLine(x.Equals(y));
}

écrit False.

La raison en est que la méthode x.Equalsa deux surcharges, une qui prend un short( System.Int16) et une qui prend un object( System.Object). Maintenant, la question est de savoir si l'un ou les deux s'appliquent à mon yargument.

Quand yest une constante de temps de compilation (littéral), le constcas, il devient important qu'il existe une conversion implicite de à int à short condition que l' intest une constante, et à condition que le compilateur C # vérifie que sa valeur est dans la plage de a short( qui 42est). Voir Conversions implicites d'expression constante dans la spécification du langage C #. Il faut donc tenir compte des deux surcharges. La surcharge Equals(short)est préférable (tout shortest un object, mais tous ne objectsont short). So yest converti en short, et cette surcharge est utilisée. EqualsCompare ensuite deux shortde valeur identique, et cela donne true.

Lorsque yn'est pas une constante, aucune conversion implicite de intà shortn'existe. En effet, en général, un intpeut être trop énorme pour tenir dans un short. (Une conversion explicite existe, mais je n'ai pas dit Equals((short)y), donc ce n'est pas pertinent.) Nous voyons qu'une seule surcharge s'applique, celle- Equals(object)là. yEst donc encadré object. Ensuite, Equalsva comparer un System.Int16à un System.Int32, et puisque les types d'exécution ne sont même pas d'accord, cela donnera false.

Nous concluons que dans certains cas (rares), le changement d'un constmembre de type en static readonlychamp (ou dans l'autre sens, lorsque cela est possible) peut changer le comportement du programme.

Jeppe Stig Nielsen
la source
17
Un bon ajout à la réponse acceptée. Je voudrais ajouter que la conversion appropriée des types de données et d'autres directives similaires (comme essayer les captures, etc.) devrait être un incontournable des programmeurs expérimentés et ne pas être laissée au compilateur. Néanmoins, j'ai appris quelque chose de nouveau d'ici. Je vous remercie.
Uknight
Wow, je programme en C # depuis longtemps et je n'aurais jamais pensé qu'un const int dans la plage d'un court-circuit pourrait être implicitement converti en court-circuit. Je dois dire que c'est plutôt étrange. J'adore C # mais ces incohérences étranges qui ne semblent pas ajouter beaucoup de valeur mais ajoutent beaucoup de puissance cérébrale requise à considérer constamment peuvent être ennuyeuses, surtout pour les débutants.
Mike Marynowski
@MikeMarynowski C'est vrai. Mais je pense qu'ils ont fait cette règle (entre autres raisons) pour rendre la déclaration short x = 42;légale. Parce que là, vous avez un int, à savoir le littéral 42, qui est implicitement transformé en short x. Mais alors, ils auraient pu limiter cela à des littéraux uniquement numériques; cependant, ils ont choisi d'autoriser également des choses comme short x = y;yest défini comme const int y = 42;, puis ils se sont retrouvés avec cela.
Jeppe Stig Nielsen
88

Une chose à noter est que const est limité aux types primitifs / valeur (à l'exception des chaînes)

Chris S
la source
30
En fait, constpourrait également être utilisé pour d'autres types, sauf qu'il doit être initialisé à null, ce qui le rend inutile :)
nawfal
6
exception comme dans System.Exception? :)
Memet Olsen
4
@nawfal Plus précisément, les seuls types de valeurs pour lesquels constpeuvent être utilisés, sont sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, plus tous les enumtypes. constne peut pas être utilisé pour d'autres types de valeurs, comme DateTimeou TimeSpanou BigInteger. Il ne peut pas non plus être utilisé pour la IntPtrstructure (considéré comme un type "primitif" par certains; le terme type primitif prête à confusion en C #). ↵↵ Le constpeut être utilisé pour tous les types de référence . Si le type est string, n'importe quelle valeur de chaîne peut être spécifiée. Sinon, la valeur doit être null.
Jeppe Stig Nielsen
@JeppeStigNielsen - J'ai récemment eu un argument avec servy à ce sujet - il a souligné que vous pouvez faire n'importe quoi (types de valeur et de référence) en constutilisant default. Pour les structtypes, il s'agit d'une instance avec tous ses membres définis sur les valeurs par défaut.
Wai Ha Lee
28

Statique en lecture seule : la valeur peut être modifiée via le staticconstructeur lors de l'exécution. Mais pas via la fonction membre.

Constante : par défaut static. La valeur ne peut pas être modifiée de n'importe où (Ctor, Function, runtime etc no-where).

Lecture seule : la valeur peut être modifiée via le constructeur lors de l'exécution. Mais pas via la fonction membre.

Vous pouvez consulter mes types de propriétés repo: C # .

Yeasin Abedin Siam
la source
1
Mauvaise nouvelle ... lien cassé!
Fer R
Bons extraits Siam ভাই :)
Muhammad Ashikuzzaman
25

Le readonlymot-clé est différent du constmot - clé. Un constchamp ne peut être initialisé qu'à la déclaration du champ. Un readonlychamp peut être initialisé soit à la déclaration, soit dans un constructeur. Par conséquent, les readonlychamps peuvent avoir des valeurs différentes selon le constructeur utilisé. De plus, même si un constchamp est une constante de compilation, le readonlychamp peut être utilisé pour les constantes d'exécution

Référence MSDN courte et claire ici

yazanpro
la source
16

constet readonlysont similaires, mais ils ne sont pas exactement les mêmes.

Un constchamp est une constante au moment de la compilation, ce qui signifie que cette valeur peut être calculée au moment de la compilation. Un readonlychamp permet des scénarios supplémentaires dans lesquels du code doit être exécuté lors de la construction du type. Après la construction, unreadonly champ ne peut pas être modifié.

Par exemple, les constmembres peuvent être utilisés pour définir des membres comme:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

Puisque les valeurs comme 3.14 et 0 sont des constantes au moment de la compilation. Cependant, considérez le cas où vous définissez un type et souhaitez en fournir des instances préfabriquées. Par exemple, vous souhaiterez peut-être définir une classe Color et fournir des "constantes" pour les couleurs courantes comme le noir, le blanc, etc. On pourrait le faire avec des membres statiques réguliers:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red   = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

Mais alors, rien n'empêche un client de Color de s'en occuper, peut-être en échangeant les valeurs Noir et Blanc. Inutile de dire que cela provoquerait la consternation pour les autres clients de la classe Color. La fonctionnalité "en lecture seule" résout ce scénario.

En introduisant simplement le readonlymot - clé dans les déclarations, nous préservons l'initialisation flexible tout en empêchant le code client de contourner.

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red   = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue  = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) => (red, green, blue) = (r, g, b);
}

Il est intéressant de noter que les membres const sont toujours statiques, alors qu'un membre en lecture seule peut être statique ou non, tout comme un champ normal.

Il est possible d'utiliser un seul mot-clé à ces deux fins, mais cela entraîne des problèmes de version ou des problèmes de performances. Supposons un instant que nous ayons utilisé un seul mot-clé pour cela (const) et un développeur a écrit:

public class A
{
    public static const C = 0;
}

et un développeur différent a écrit du code qui s'appuyait sur A:

public class B
{
    static void Main() => Console.WriteLine(A.C);
}

Maintenant, le code généré peut-il s'appuyer sur le fait que AC est une constante de temps de compilation? C'est-à-dire, l'utilisation de AC peut-elle simplement être remplacée par la valeur 0? Si vous dites "oui" à cela, cela signifie que le développeur de A ne peut pas changer la façon dont AC est initialisé - cela lie les mains du développeur de A sans autorisation.

Si vous dites «non» à cette question, une optimisation importante est manquée. L'auteur de A est peut-être certain que AC sera toujours nul. L'utilisation de const et readonly permet au développeur de A de spécifier l'intention. Cela permet un meilleur comportement de version et également de meilleures performances.

Ramesh Rajendran
la source
12

Ma préférence est d'utiliser const chaque fois que je le peux, ce qui, comme mentionné ci-dessus, est limité aux expressions littérales ou à quelque chose qui ne nécessite pas d'évaluation.

Si je me heurte à cette limitation, je retombe en statique uniquement , avec une mise en garde. J'utiliserais généralement une propriété statique publique avec un getter et un champ privé statique en lecture seule comme Marc le mentionne ici .

Peter Meyer
la source
7

Const: Const n'est rien d'autre que "constant", une variable dont la valeur est constante mais au moment de la compilation. Et il est obligatoire de lui attribuer une valeur. Par défaut, un const est statique et nous ne pouvons pas changer la valeur d'une variable const dans tout le programme.

Static ReadOnly: la valeur d'une variable de type Static Readonly peut être affectée au moment de l'exécution ou affectée au moment de la compilation et modifiée au moment de l'exécution. Mais la valeur de cette variable ne peut être modifiée que dans le constructeur statique. Et ne peut plus être modifié. Il ne peut changer qu'une seule fois lors de l'exécution

Référence: c-sharpcorner

mayank
la source
6

Un champ en lecture seule statique est avantageux lors de l'exposition à d'autres assemblys d'une valeur qui pourrait changer dans une version ultérieure.

Par exemple, supposons que l'assembly Xexpose une constante comme suit:

public const decimal ProgramVersion = 2.3;

Si l'assembly Yréférence Xet utilise cette constante, la valeur 2.3 sera intégrée à l'assembly Ylors de la compilation. Cela signifie que si Xest recompilé plus tard avec la constante définie à 2,4, Yutilisera toujours l'ancienne valeur de 2,3 jusqu'à ce qu'il Ysoit recompilé. Un champ en lecture seule statique évite ce problème.

Une autre façon de voir les choses est que toute valeur qui pourrait changer à l'avenir n'est pas constante par définition, et ne devrait donc pas être représentée comme une seule.

Yagnesh Cangi
la source
3

const:

  1. la valeur doit être donnée lors de la déclaration
  2. compiler la constante de temps

lecture seulement:

  1. La valeur peut être donnée lors de la déclaration ou lors de l'exécution à l'aide de constructeurs. La valeur peut varier selon le constructeur utilisé.
  2. constante de temps d'exécution
dasumohan89
la source
3

Const : les valeurs des variables const doivent être définies avec la déclaration et après cela, elles ne changeront pas. const sont implicitement statiques, donc sans créer d'instance de classe, nous pouvons y accéder. cela a une valeur au moment de la compilation

ReadOnly : valeurs de variable en lecture seule que nous pouvons définir tout en déclarant ainsi qu'en utilisant le constructeur lors de l'exécution. les variables en lecture seule ne peuvent pas accéder sans instance de classe.

Static readonly : valeurs de variables statiques en lecture seule que nous pouvons définir tout en déclarant ainsi que par le biais d'un constructeur statique mais pas avec tout autre constructeur.Ces variables sont également accessibles sans créer d'instance de classe (en tant que variables statiques).

la lecture statique seule sera un meilleur choix si nous devons consommer les variables dans différents assemblages.Veuillez vérifier les détails complets dans le lien ci-dessous

https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/

user1756922
la source
Pourriez-vous me dire pourquoi vous avez voté contre la réponse, afin que je puisse me mettre à jour ainsi qu'ici.
user1756922
Pas le DV, mais il se peut que cette réponse n'ajoute vraiment rien aux réponses déjà complètes ici.
Marc L.
en effet, rappelez-vous qu'à Java à la fin des années 90, nous avions dans un projet plusieurs personnes produisant différents fichiers jar avec des fichiers de classe qui interopéraient (se référençaient) et la chaîne de const publique avait des problèmes de version, car ils étaient copiés
George Birbilis
2

Il existe une différence mineure entre les champs const et statiques en lecture seule dans C # .Net

const doit être initialisé avec une valeur au moment de la compilation.

const est par défaut statique et doit être initialisé avec une valeur constante, qui ne peut pas être modifiée ultérieurement. Il ne peut pas être utilisé avec tous les types de données. Par exemple DateTime. Il ne peut pas être utilisé avec le type de données DateTime.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public static readonly string Name = string.Empty; //No error, legal

readonly peut être déclaré comme statique, mais pas nécessaire. Pas besoin d'initialiser au moment de la déclaration. Sa valeur peut être attribuée ou modifiée à l'aide du constructeur une fois. Il y a donc une possibilité de changer une fois la valeur du champ en lecture seule (peu importe, s'il est statique ou non), ce qui n'est pas possible avec const.

Chirag
la source
0

Les constantes sont comme le nom l'indique, les champs qui ne changent pas et sont généralement définis statiquement au moment de la compilation dans le code.

Les variables en lecture seule sont des champs qui peuvent changer dans des conditions spécifiques.

Ils peuvent être soit initialisés lorsque vous les déclarez pour la première fois comme une constante, mais ils sont généralement initialisés lors de la construction de l'objet à l'intérieur du constructeur.

Ils ne peuvent pas être modifiés après l'initialisation, dans les conditions mentionnées ci-dessus.

La lecture statique seule me semble un mauvais choix car, si elle est statique et qu'elle ne change jamais, utilisez-la simplement public const, si elle peut changer, ce n'est pas une constante, puis, selon vos besoins, vous pouvez soit utiliser read -seulement ou simplement une variable régulière.

En outre, une autre distinction importante est qu'une constante appartient à la classe, tandis que la variable en lecture seule appartient à l'instance!

Claudiu Cojocaru
la source
0

Un const (étant déterminé au moment de la compilation) peut être utilisé dans les cas où une statique en lecture seule ne peut pas, comme dans les instructions switch ou les constructeurs d'attribut. En effet, les champs en lecture seule ne sont résolus qu'au moment de l'exécution et certaines constructions de code nécessitent une assurance de temps de compilation. Une statique en lecture seule peut être calculée dans un constructeur, ce qui est souvent une chose essentielle et utile. La différence est fonctionnelle, comme devrait l'être leur utilisation à mon avis.

En termes d'allocation de mémoire, au moins avec les chaînes (étant un type de référence), il ne semble pas y avoir de différence dans la mesure où les deux sont internés et référenceront la seule instance internée.

Personnellement, ma valeur par défaut est statique en lecture seule, car elle a plus de sens sémantique et logique pour moi, d'autant plus que la plupart des valeurs ne sont pas nécessaires au moment de la compilation. Et, en passant, la statique publique en lecture seule n'est pas inhabituelle ou rare du tout comme l'indique la réponse marquée: par exemple, System.String.Emptyest un.

DvS
la source
0

Une autre différence entre déclarer const et statique en lecture seule réside dans l'allocation de mémoire.

Un champ statique appartient au type d'un objet plutôt qu'à une instance de ce type. Par conséquent, une fois que la classe est référencée pour la première fois, le champ statique "vivra" dans la mémoire pour le reste du temps et la même instance du champ statique sera référencée par toutes les instances du type.

En revanche, un champ const "appartient à une instance du type.

Si la mémoire de désallocation est plus importante pour vous, préférez utiliser const . Si la vitesse, alors utilisez statique en lecture seule .

Boris Lipschitz
la source