[c#] Statique readonly vs const



Answers

J'utiliserais static readonly si le consommateur est dans un assemblage différent. Avoir le const et le consommateur dans deux assemblées différentes est une belle façon de se tirer une balle dans le pied .

Question

J'ai lu autour de const et static readonly champs en static readonly . Nous avons quelques classes qui ne contiennent que des valeurs constantes. Utilisé pour diverses choses dans notre système. Donc je me demande si mon observation est correcte:

Est-ce que ce genre de valeurs constantes doit toujours être static readonly pour tout ce qui est public? Et seulement utiliser const pour les valeurs internes / protégées / privées?

Que recommandez-vous? Est-ce que je devrais peut-être même ne pas utiliser static readonly champs static readonly , mais plutôt utiliser des propriétés?




Le mot-clé readonly est différent du mot-clé const . Un champ const ne peut être initialisé qu'à la déclaration du champ. Un champ readonly peut être initialisé soit à la déclaration, soit dans un constructeur. Par conséquent, les champs en readonly peuvent avoir des valeurs différentes selon le constructeur utilisé. De plus, alors qu'un champ const est une constante à la compilation, le champ readonly peut être utilisé pour les constantes d'exécution

Référence MSDN courte et claire ici




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

Par exemple, supposons que l'assemblage X expose une constante comme suit:

public const decimal ProgramVersion = 2.3;

Si l'assembly Y référence X et utilise cette constante, la valeur 2.3 sera cuite dans l'ensemble Y lors de la compilation. Cela signifie que si X est recompilé plus tard avec la constante définie sur 2.4, Y utilisera toujours l'ancienne valeur de 2.3 jusqu'à ce que Y soit recompilé. Un champ statique en lecture seule évite ce problème.

Une autre façon de voir cela est que toute valeur qui pourrait changer dans le futur n'est pas constante par définition, et ne devrait donc pas être représentée comme telle.




Ceci est juste un complément aux autres réponses. Je ne vais pas les répéter (maintenant quatre ans plus tard).

Il y a des situations où un const et 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));
}

imprime True , alors 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.Equals a 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 avec mon argument y .

Lorsque y est une constante à la compilation (literal), le cas const , il devient important qu'il existe une conversion implicite d' int à short condition que l' int soit une constante et que le compilateur C # vérifie que sa valeur est comprise dans la gamme d'un short (qui 42 est). Voir Conversions d'expressions constantes implicites dans la spécification de langage C #. Donc les deux surcharges doivent être considérées. La surcharge Equals(short) est préférée (tout short est un object , mais tous les object sont pas short ). Donc y est converti en short , et cette surcharge est utilisée. Ensuite, Equals compare deux valeurs short identiques, ce qui donne true .

Lorsque y n'est pas une constante, aucune conversion implicite d' int en short n'existe. En effet, en général, un int peut être trop grand 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, la valeur Equals(object) . Donc y est encadré pour object . Puis Equals va 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), changer un membre de type const en un static readonly (ou dans l'autre sens, quand cela est possible) peut changer le comportement du programme.




const:

  1. valeur devrait ê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 pendant l'exécution en utilisant des constructeurs. La valeur peut varier selon le constructeur utilisé.
  2. durée d'exécution constante



Const et readonly sont similaires, mais ils ne sont pas exactement les mêmes. Un champ const est une constante à la compilation, ce qui signifie que cette valeur peut être calculée au moment de la compilation. Un champ readonly active des scénarios supplémentaires dans lesquels du code doit être exécuté pendant la construction du type. Après la construction, un champ en lecture seule ne peut pas être modifié.

Par exemple, les membres const 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 de compilation. Cependant, considérez le cas où vous définissez un type et souhaitez en fournir quelques exemples. Par exemple, vous pouvez définir une classe Color et fournir des "constantes" pour les couleurs courantes comme Noir, Blanc, etc. Il n'est pas possible de faire cela avec les membres const, car les côtés droits ne sont pas des constantes de compilation. 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 = r;
        green = g;
        blue = b;
    }
}

mais alors il n'y a rien pour empêcher un client de Color de le faire, peut-être en échangeant les valeurs Black et White. Inutile de dire que cela causerait de la consternation pour les autres clients de la classe Color. La fonctionnalité "en lecture seule" traite ce scénario. En introduisant simplement le mot clé readonly dans les déclarations, nous préservons l'initialisation flexible tout en empêchant le code client de déraper.

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 = r;
        green = g;
        blue = b;
    }
}

Il est intéressant de noter que les membres const sont toujours statiques, tandis 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é pour ces deux objectifs, mais cela entraîne des problèmes de version ou de performances. Supposons un instant que nous avons utilisé un seul mot-clé pour ce (const) et un développeur a écrit:

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

et un développeur différent a écrit un 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 compilation? Autrement dit, l'utilisation de AC peut-elle simplement être remplacée par la valeur 0? Si vous dites "oui" à ceci, cela signifie que le développeur de A ne peut pas changer la façon dont AC est initialisé - ceci lie les mains du développeur de A sans permission. Si vous dites "non" à cette question, une optimisation importante est manquée. Peut-être que l'auteur de A est positif que AC sera toujours zéro. L'utilisation de const et de readonly permet au développeur de A de spécifier l'intention. Cela améliore le comportement de gestion des versions et améliore les performances.




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 initialisés lorsque vous les déclarez d'abord comme une constante, mais ils sont généralement initialisés lors de la construction de l'objet dans le constructeur.

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

Statique en lecture seule me semble un mauvais choix puisque, si c'est statique et ça ne change jamais, alors utilisez le public const, si ça peut changer alors ce n'est pas une constante et ensuite, selon vos besoins, vous pouvez soit utiliser read -seulement ou juste 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!




Related



Tags

c# c#   constants