c# property - Quelle est la différence entre const et readonly?




static array (25)

Encore un autre gotcha: les valeurs en lecture seule peuvent être modifiées par le code "sournois" via la réflexion.

var fi = this.GetType()
             .BaseType
             .GetField("_someField", 
                       BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);

Puis-je modifier un champ hérité readonly privé en C # en utilisant la réflexion?

Quelle est la différence entre const et readonly et utilisez-vous l'un par rapport à l'autre?


En dehors de la différence apparente de

  • avoir à déclarer la valeur au moment de la définition d'une const VS readonly valeurs peuvent être calculées dynamiquement, mais doivent être assignées avant que le constructeur se termine .. après qu'il est gelé.
  • Les const sont implicitement static . Vous utilisez une notation ClassName.ConstantName pour y accéder.

Il y a une différence subtile. Considérons une classe définie dans AssemblyA .

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly int I_RO_VALUE;
  public Const_V_Readonly()
  {
     I_RO_VALUE = 3;
  }
}

AssemblyB référence à AssemblyA et utilise ces valeurs dans le code. Quand cela est compilé,

  • dans le cas de la valeur const , c'est comme un find-replace, la valeur 2 est «cuite» dans l'IL de l' AssemblyB . Cela signifie que si demain je vais mettre à jour I_CONST_VALUE à 20 dans le futur. AssemblyB aurait encore 2 jusqu'à ce que je le recompile .
  • dans le cas de la valeur readonly , c'est comme une ref à un emplacement de mémoire. La valeur n'est pas incorporée dans IL de AssemblyB . Cela signifie que si l'emplacement de mémoire est mis à jour, AssemblyB obtient la nouvelle valeur sans recompilation. Donc, si I_RO_VALUE est mis à jour à 30, il vous suffit de construire AssemblyA . Tous les clients n'ont pas besoin d'être recompilés.

Donc, si vous êtes sûr que la valeur de la constante ne changera pas, utilisez un const .

public const int CM_IN_A_METER = 100;

Mais si vous avez une constante qui peut changer (précision egwrt) .. ou en cas de doute, utilisez un readonly .

public readonly float PI = 3.14;

Mise à jour: Aku a besoin d'une mention car il l'a signalé en premier. Aussi j'ai besoin de brancher où j'ai appris cela .. Effective C # - Bill Wagner


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 lecture seule peuvent avoir des valeurs différentes selon le constructeur utilisé. De même, alors qu'un champ const est une constante à la compilation, le champ readonly peut être utilisé pour les constantes d'exécution comme dans l'exemple suivant:

public static readonly uint l1 = (uint) DateTime.Now.Ticks;

Une constante sera compilée dans le consommateur en tant que valeur littérale tandis que la chaîne statique servira de référence à la valeur définie.

Comme exercice, essayez de créer une bibliothèque externe et consommez-la dans une application console, puis modifiez les valeurs dans la bibliothèque et recompilez-la (sans recompiler le programme consommateur), déposez la DLL dans le répertoire et exécutez manuellement le fichier EXE, vous devriez trouver que la chaîne constante ne change pas.


Cela l'explique . Résumé: const doit être initialisé au moment de la déclaration, readonly peut être initialisé sur le constructeur (et avoir ainsi une valeur différente selon le constructeur utilisé).

EDIT: Voir Gotcha Gishu ci-dessus pour la différence subtile


Juste pour ajouter, ReadOnly pour les types de référence ne fait que la référence en lecture seule et non les valeurs. Par exemple:

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};

  public UpdateReadonly()
  {
     I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
     I_RO_VALUE = new char[]{'V'}; //will cause compiler error
  }
}

Un const doit être codé en dur , où readonly peut être défini dans le constructeur de la classe.


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 lecture seule peuvent avoir des valeurs différentes selon le constructeur utilisé. De même, alors qu'un champ const est une constante à la compilation , le champ readonly peut être utilisé pour les constantes d' exécution comme dans l'exemple suivant:

public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;

Une chose à ajouter à ce que les gens ont dit plus haut. Si vous avez un assembly contenant une valeur readonly (par exemple readonly MaxFooCount = 4;), vous pouvez changer la valeur que les assemblys appelants voient en envoyant une nouvelle version de cet assembly avec une valeur différente (par exemple readonly MaxFooCount = 5;)

Mais avec un const, il serait plié dans le code de l'appelant lorsque l'appelant a été compilé.

Si vous avez atteint ce niveau de compétence C #, vous êtes prêt pour le livre de Bill Wagner, Effective C #: 50 façons spécifiques d'améliorer votre C # Qui répond à cette question en détail, (et 49 autres choses).


Les variables marquées const sont un peu plus que des macros #define fortement typées, au moment de la compilation les références de variables const sont remplacées par des valeurs littérales en ligne. Par conséquent, seuls certains types de valeur primitive intégrés peuvent être utilisés de cette manière. Les variables marquées readonly peuvent être définies, dans un constructeur, lors de l'exécution et leur lecture seule est également appliquée pendant l'exécution. Cela implique des coûts de performance minimes, mais cela signifie que vous pouvez utiliser readonly avec n'importe quel type (même les types de référence).

De plus, les variables const sont intrinsèquement statiques, tandis que les variables readonly peuvent être spécifiques à l'instance si vous le souhaitez.


Constantes

  • Les constantes sont statiques par défaut
  • Ils doivent avoir une valeur au moment de la compilation (vous pouvez avoir par exemple 3.14 * 2, mais ne peuvent pas appeler les méthodes)
  • Pourrait être déclaré dans les fonctions
  • Sont copiés dans chaque assembly qui les utilise (chaque assembly obtient une copie locale des valeurs)
  • Peut être utilisé dans les attributs

En lecture seule les champs d'instance

  • Doit avoir une valeur définie, au moment où le constructeur quitte
  • Sont évalués lors de la création de l'instance

Champs statiques en lecture seule

  • Sont évalués lorsque l'exécution du code atteint la référence de la classe (lorsqu'une nouvelle instance est créée ou qu'une méthode statique est exécutée)
  • Doit avoir une valeur évaluée au moment où le constructeur statique est terminé
  • Il n'est pas recommandé d'y ajouter ThreadStaticAttribute (les constructeurs statiques seront exécutés dans un seul thread et définiront la valeur de son thread, tous les autres threads auront cette valeur non initialisée)

Lecture seule : La valeur peut être modifiée via Ctor à l'exécution. Mais pas à travers la fonction de membre

Constante : Par défaut statique. La valeur ne peut pas être changée de n'importe où (Ctor, Function, runtime etc.


Voici un autre lien montrant comment const n'est pas sûr pour la version, ou pertinent pour les types de référence.

Résumé :

  • La valeur de votre propriété const est définie au moment de la compilation et ne peut pas changer à l'exécution
  • Const ne peut pas être marqué comme statique - le mot-clé indique qu'ils sont statiques, contrairement aux champs readonly qui le peuvent.
  • Const ne peut être autre chose que des types de valeur (primitive)
  • Le mot clé readonly marque le champ comme non modifiable. Cependant, la propriété peut être modifiée dans le constructeur de la classe
  • Le seul mot-clé readonly peut également être combiné avec static pour le faire agir de la même manière qu'un const (atleast sur la surface). Il y a une différence marquée quand on regarde l'IL entre les deux
  • Les champs const sont marqués "literal" dans IL tandis que readonly est "initonly"

Les variables constantes sont déclarées et initialisées au moment de la compilation. La valeur ne peut pas être modifiée après. Les variables en lecture seule seront initialisées uniquement à partir du constructeur statique de la classe. Read only est utilisé uniquement lorsque nous voulons affecter la valeur au moment de l'exécution.


L'un des membres de l'équipe de notre bureau a fourni les indications suivantes sur l'utilisation de const, static et readonly:

  • Utilisez const lorsque vous avez une variable d'un type que vous pouvez connaître au moment de l'exécution (chaîne littérale, int, double, enums, ...) à laquelle vous voulez que toutes les instances ou consommateurs d'une classe aient accès où la valeur ne devrait pas changer.
  • Utilisez static lorsque vous possédez des données auxquelles vous souhaitez que toutes les instances ou utilisateurs d'une classe aient accès, là où la valeur peut changer.
  • Utilisez static readonly lorsque vous avez une variable d'un type que vous ne pouvez pas savoir au moment de l'exécution (objets) et à laquelle toutes les instances ou les utilisateurs d'une classe doivent avoir accès lorsque la valeur ne doit pas changer.
  • Utilisez readonly lorsque vous avez une variable de niveau d'instance que vous saurez au moment de la création de l'objet qui ne devrait pas changer.

Une dernière remarque: un champ const est statique, mais l'inverse n'est pas vrai.


Un const est une constante à la compilation alors que readonly permet de calculer une valeur à l'exécution et de l'initialiser dans le constructeur ou dans le champ. Donc, un 'const' est toujours constant mais 'readonly' est en lecture seule une fois qu'il est assigné.

Eric Lippert de l'équipe C # a plus d'informations sur les différents types d'immutabilité


Il y a un petit gotcha avec readonly. Un champ en lecture seule peut être défini plusieurs fois dans le (s) constructeur (s). Même si la valeur est définie dans deux constructeurs chaînés différents, elle est toujours autorisée.


public class Sample {
    private readonly string ro;

    public Sample() {
        ro = "set";
    }

    public Sample(string value) : this() {
        ro = value; // this works even though it was set in the no-arg ctor
    }
}

Principalement; Vous pouvez assigner une valeur à un champ statique en lecture seule à une valeur non constante au moment de l'exécution, tandis qu'une valeur constante doit être affectée à const.


Il y a une différence notable entre les champs const et readonly dans C # .Net

const est par défaut statique et doit être initialisé avec une valeur constante, qui ne peut pas être modifiée plus tard. Le changement de valeur n'est pas autorisé dans les constructeurs aussi. Il ne peut pas être utilisé avec tous les types de données. Pour ex-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 readonly string Name = string.Empty; //No error, legal

readonly peut être déclaré statique, mais pas nécessaire. Pas besoin de s'initialiser au moment de la déclaration. Sa valeur peut être affectée ou modifiée en utilisant le constructeur. Donc, cela donne un avantage lorsqu'il est utilisé comme membre de classe d'instance. Deux instanciations différentes peuvent avoir une valeur différente de champ en lecture seule. Par ex -

class A
{
    public readonly int Id;

    public A(int i)
    {
        Id = i;
    }
}

Le champ readonly peut alors être initialisé avec des valeurs spécifiques instantanées, comme suit:

A objOne = new A(5);
A objTwo = new A(10);

Ici, l'instance objOne aura la valeur du champ readonly comme 5 et objTwo a 10. Ce qui n'est pas possible en utilisant const.


Un membre constant est défini au moment de la compilation et ne peut pas être modifié au moment de l'exécution. Les constantes sont déclarées comme un champ, en utilisant le mot-clé const et doivent être initialisées comme elles sont déclarées.

public class MyClass
{
    public const double PI1 = 3.14159;
}

Un membre en readonly est comme une constante en ce sens qu'il représente une valeur immuable. La différence est qu'un membre readonly peut être initialisé au moment de l'exécution, dans un constructeur, tout en pouvant être initialisé à mesure qu'ils sont déclarés.

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

const

  • Ils ne peuvent pas être déclarés static (ils sont implicitement statiques)
  • La valeur de constante est évaluée au moment de la compilation
  • les constantes sont initialisées à la déclaration seulement

lecture seulement

  • Ils peuvent être au niveau de l'instance ou statiques
  • La valeur est évaluée au moment de l'exécution
  • readonly peut être initialisé dans la déclaration ou par le code dans le constructeur

Constant

Nous devons fournir la valeur au champ const quand il est défini. Le compilateur enregistre ensuite la valeur de la constante dans les métadonnées de l'assembly. Cela signifie qu'une constante peut être définie uniquement pour le type primitif comme boolean, char, byte, etc. Les constantes sont toujours considérées comme des membres statiques et non comme des membres d'instance.

Lecture seulement

Les zones en lecture seule ne peuvent être résolues qu'à l'exécution. Cela signifie que nous pouvons définir une valeur pour une valeur en utilisant le constructeur pour le type dans lequel le champ est déclaré. La vérification est effectuée par le compilateur que les champs en lecture seule ne sont pas écrits par une méthode autre que le constructeur.

Plus d'informations sur les deux expliqué ici dans cet article


Un autre gotcha .

Puisque const ne fonctionne vraiment qu'avec des types de données basiques, si vous voulez travailler avec une classe, vous pouvez vous sentir "forcé" à utiliser ReadOnly. Cependant, méfiez-vous du piège! ReadOnly signifie que vous ne pouvez pas remplacer l'objet par un autre objet (vous ne pouvez pas le faire se référer à un autre objet). Mais tout processus qui a une référence à l'objet est libre de modifier les valeurs à l' intérieur de l'objet!

Donc ne soyez pas confus en pensant que ReadOnly implique qu'un utilisateur ne peut pas changer les choses. Il n'y a pas de syntaxe simple en C # pour empêcher une instanciation d'une classe de changer ses valeurs internes (pour autant que je sache).


const : Impossible de changer n'importe où.

readonly : cette valeur ne peut être modifiée que dans le constructeur. Ne peut pas être changé dans les fonctions normales.


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.


Oui, const est défini au moment de la compilation et les états nikic ne peuvent pas être affectés d'une expression, comme peut le définir (). Mais aussi const ne peut pas être déclaré conditionnellement (pour la même raison). c'est à dire. Tu ne peux pas faire ça:

if (/* some condition */) {
  const WHIZZ = true;  // CANNOT DO THIS!
}

Alors que vous pourriez avec un define (). Donc, il ne s'agit pas vraiment d'une préférence personnelle, il y a une bonne et une mauvaise façon d'utiliser les deux.

En aparté ... J'aimerais voir une sorte de const de classe qui peut être assignée à une expression, une sorte de define () qui peut être isolée des classes?





c# .net const constants readonly