Quelle est la différence entre const
et readonly
en C #?
Quand utiliseriez-vous l'un sur l'autre?
Quelle est la différence entre const
et readonly
en C #?
Quand utiliseriez-vous l'un sur l'autre?
Réponses:
Outre la différence apparente de
const
VS readonly
peut être calculé dynamiquement mais doit être assigné avant que le constructeur ne quitte .. après cela il est figé.static
. Vous utilisez une ClassName.ConstantName
notation pour y accéder.Il y a une subtile différence. 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. Lorsque cela est compilé,
const
valeur, c'est comme un find-replace, la valeur 2 est «cuite dans» l' AssemblyB
IL du. Cela signifie que si demain je mettrai à jour I_CONST_VALUE
20 à l'avenir. AssemblyB
aurait encore 2 jusqu'à ce que je le recompile .readonly
valeur, c'est comme un ref
vers un emplacement mémoire. La valeur n'est pas intégrée dans AssemblyB
l'IL de. Cela signifie que si l'emplacement 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 a 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 a readonly
.
public readonly float PI = 3.14;
Mise à jour: Aku doit obtenir une mention parce qu'il l'a d'abord signalé. J'ai aussi besoin de brancher où j'ai appris cela .. C # efficace - Bill Wagner
static
point semble être le point le plus important et le plus utile -consts are implicitly static
readonly
les variables peuvent être modifiées en dehors du constructeur (réflexion). Ce n'est que le compilateur qui essaie de vous empêcher de modifier la var en dehors du constructeur.
readonly
variables @ mini-me ne peuvent pas être modifiées une fois que le constructeur a terminé, même par réflexion. Le runtime n'arrive pas à appliquer cela. Le runtime n'arrive pas non plus à appliquer ce que vous ne changez string.Empty
pas "Hello, world!"
, mais je ne dirais toujours pas que cela rend string.Empty
modifiable, ou que le code ne devrait pas supposer que ce string.Empty
sera toujours une chaîne de longueur nulle.
Il y a un piège avec des consts! Si vous référencez une constante d'un autre assembly, sa valeur sera compilée directement dans l'assembly appelant. De cette façon, lorsque vous mettez à jour la constante dans l'assembly référencé, elle ne change pas dans l'assembly appelant!
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
}
}
string
celui que vous pourriez utiliser comme constante?
const
des types de référence autres que chaîne, mais la constante ne peut avoir que la valeur null
.
Cela explique cela . Résumé: const doit être initialisé au moment de la déclaration, readonly peut être initialisé sur le constructeur (et donc avoir une valeur différente selon le constructeur utilisé).
EDIT: Voir le gotcha de Gishu ci-dessus pour la différence subtile
Il y a un petit gotcha avec lecture seule. Un champ en lecture seule peut être défini plusieurs fois dans le ou les constructeurs. 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
}
}
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 sous forme de champ, à l'aide du const
mot clé et doivent être initialisées au fur et à mesure qu'elles sont déclarées.
public class MyClass
{
public const double PI1 = 3.14159;
}
Un readonly
membre est comme une constante en ce qu'il représente une valeur immuable. La différence est qu'un readonly
membre peut être initialisé au moment de l'exécution, dans un constructeur, tout en pouvant être initialisé lors de leur déclaration.
public class MyClass1
{
public readonly double PI2 = 3.14159;
//or
public readonly double PI3;
public MyClass2()
{
PI3 = 3.14159;
}
}
const
static
(ils sont implicitement statiques)lecture seulement
static const int i = 0;
const
déclarations ne peuvent pas être faites à l'intérieur des méthodes?
Un const est une constante de compilation tandis que la lecture seule permet de calculer une valeur au moment de l'exécution et de la définir dans le constructeur ou l'initialiseur de champ. Ainsi, un «const» est toujours constant, mais «readonly» est en lecture seule une fois qu'il est attribué.
Eric Lippert de l'équipe C # a plus d'informations sur les différents types d'immuabilité
Voici un autre lien montrant comment const n'est pas une version sûre ou pertinente pour les types de référence.
Résumé :
Lecture seule : la valeur peut être modifiée via Ctor lors de l'exécution. Mais pas via la fonction membre
Constante : par défaut statique. La valeur ne peut pas être modifiée de n'importe où (Ctor, Function, runtime etc no-where)
Encore un autre problème: les valeurs en lecture seule peuvent être modifiées par du 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é en lecture seule privé en C # en utilisant la réflexion?
Je crois qu'une const
valeur est la même pour tous les objets (et doit être initialisée avec une expression littérale), alors qu'elle readonly
peut être différente pour chaque instanciation ...
L'un des membres de l'équipe de notre bureau a fourni les conseils suivants sur le moment d'utiliser const, static et readonly:
Une dernière remarque: un champ const est statique, mais l'inverse n'est pas vrai.
Ils sont tous les deux constants, mais un const est également disponible au moment de la compilation. Cela signifie qu'un aspect de la différence est que vous pouvez utiliser des variables const comme entrée pour attribuer des constructeurs, mais pas des variables en lecture seule.
Exemple:
public static class Text {
public const string ConstDescription = "This can be used.";
public readonly static string ReadonlyDescription = "Cannot be used.";
}
public class Foo
{
[Description(Text.ConstDescription)]
public int BarThatBuilds {
{ get; set; }
}
[Description(Text.ReadOnlyDescription)]
public int BarThatDoesNotBuild {
{ get; set; }
}
}
quand utiliser const
oureadonly
const
readonly
App.config
-à- dire , mais une fois initialisée, elle ne peut pas être modifiéeLes variables marquées const sont un peu plus que des macros #define fortement typées, au moment de la compilation, les références des variables const sont remplacées par des valeurs littérales en ligne. Par conséquent, seuls certains types de valeurs primitifs intégrés peuvent être utilisés de cette manière. Les variables marquées en lecture seule peuvent être définies, dans un constructeur, au moment de l'exécution et leur lecture seule est également appliquée lors de l'exécution. Il y a un coût de performance mineur associé à cela, mais cela signifie que vous pouvez utiliser en lecture seule avec n'importe quel type (même les types de référence).
En outre, les variables const sont intrinsèquement statiques, tandis que les variables en lecture seule peuvent être spécifiques à l'instance si vous le souhaitez.
Un autre gotcha .
Puisque const ne fonctionne vraiment qu'avec les types de données de base, si vous voulez travailler avec une classe, vous pouvez vous sentir "obligé" d'utiliser ReadOnly. Attention cependant au piège! ReadOnly signifie que vous ne pouvez pas remplacer l'objet par un autre objet (vous ne pouvez pas le faire référence à 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!
Ne soyez donc 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 voir ses valeurs internes modifiées (pour autant que je sache).
Il existe 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 ultérieurement. Le changement de valeur n'est pas non plus autorisé dans les constructeurs. 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 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 affectée ou modifiée à l'aide du constructeur. Ainsi, il 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 exemple -
class A
{
public readonly int Id;
public A(int i)
{
Id = i;
}
}
Ensuite, le champ en lecture seule peut être initialisé avec des valeurs spécifiques instantanées, comme suit:
A objOne = new A(5);
A objTwo = new A(10);
Ici, instance objOne aura la valeur du champ en lecture seule comme 5 et objTwo en a 10. Ce qui n'est pas possible en utilisant const.
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.
En tant qu'exercice, essayez de créer une bibliothèque externe et de la consommer 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 EXE manuellement, vous devriez trouver que la chaîne constante ne change pas.
Constant
Nous devons fournir la valeur au champ const lorsqu'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 ne peut être définie que pour le type primitif comme booléen, char, octet, etc. Les constantes sont toujours considérées comme des membres statiques et non comme des membres d'instance.
Lecture seulement
Les champs en lecture seule ne peuvent être résolus qu'au moment de 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 sur les deux expliqués ici dans cet article
Const et readonly sont similaires, mais ils ne sont pas exactement les mêmes. Un champ const est une constante au moment de la compilation, ce qui signifie que cette valeur peut être calculée au moment de la compilation. Un champ en lecture seule permet des scénarios supplémentaires dans lesquels du code doit être exécuté lors de 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 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 = r;
green = g;
blue = b;
}
}
mais alors il n'y a rien pour empêcher 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 mot-clé en lecture seule 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 = r;
green = g;
blue = 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.
La différence est que la valeur d'un champ en lecture seule statique est définie au moment de l'exécution, de sorte qu'il peut avoir une valeur différente pour différentes exécutions du programme. Cependant, la valeur d'un champ const est définie sur une constante de temps de compilation.
N'oubliez pas: pour les types de référence, dans les deux cas (statique et instance), le modificateur en lecture seule vous empêche uniquement d'attribuer une nouvelle référence au champ. Elle ne rend pas spécifiquement immuable l'objet visé par la référence.
Pour plus de détails, veuillez consulter la foire aux questions C # sur ce sujet: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx
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 quartiers. Les variables en lecture seule seront initialisées uniquement à partir du constructeur statique de la classe. La lecture seule est utilisée uniquement lorsque nous voulons affecter la valeur au moment de l'exécution.
Const : valeur constante absolue pendant la durée de vie de l'application.
Lecture seule : il peut être modifié en temps d'exécution.
Une chose à ajouter à ce que les gens ont dit ci-dessus. Si vous avez un assembly contenant une valeur en lecture seule (par exemple, readonly MaxFooCount = 4;), vous pouvez modifier la valeur que les assemblys appelants voient en expédiant une nouvelle version de cet assembly avec une valeur différente (par exemple readonly MaxFooCount = 5;)
Mais avec un const, il serait intégré au code de l'appelant lors de la compilation de l'appelant.
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).