Question

Une erreur du compilateur CS0283 indique que seul le Les types de POD de base (ainsi que les chaînes, les énumérations et les références nulles) peuvent être déclarés comme const . Quelqu'un at-il une théorie sur la raison de cette limitation? Par exemple, il serait intéressant de pouvoir déclarer des valeurs const d’autres types, telles que IntPtr.

Je pense que le concept de const est en fait un sucre syntaxique en C # et qu'il ne fait que remplacer toute utilisation du nom par la valeur littérale. Par exemple, étant donné la déclaration suivante, toute référence à Foo serait remplacée par "foo". au moment de la compilation.

const string Foo = "foo";

Ceci éliminerait les types mutables, alors peut-être qu'ils ont choisi cette limitation plutôt que de devoir déterminer au moment de la compilation si un type donné est mutable?

Était-ce utile?

La solution

Extrait de la spécification C #, chapitre 10.4 - Constantes :
(10.4 dans la spécification C # 3.0, 10.3 dans la version en ligne pour 2.0)

  

Une constante est un membre de la classe qui représente une valeur constante: une valeur pouvant être calculée lors de la compilation.

Cela signifie que vous ne pouvez utiliser que des expressions composées uniquement de littéraux. Tous les appels à des méthodes, les constructeurs (qui ne peuvent pas être représentés sous la forme de littéraux IL purs) ne peuvent pas être utilisés, car le compilateur n'a aucun moyen d'effectuer cette exécution et donc de calculer les résultats au moment de la compilation. De plus, comme il n’existe aucun moyen de marquer une méthode comme invariante (c’est-à-dire qu’il existe un mappage un-à-un entre entrée et sortie), la seule façon pour le compilateur de le faire serait d’analyser l’IL pour voir si cela dépend de choses autres que les paramètres d'entrée, le traitement spécial de certains types (comme IntPtr), ou tout simplement l'interdiction d'appeler n'importe quel code.

IntPtr, par exemple, bien qu’il s’agisse d’un type de valeur, reste une structure et non l’un des littéraux intégrés. En tant que tel, toute expression utilisant un IntPtr devra appeler du code dans la structure IntPtr, ce qui n’est pas légal pour une déclaration constante.

Le seul exemple de type de valeur constante juridique auquel je puisse penser est celui qui est initialisé avec des zéros en le déclarant, ce qui n’est guère utile.

Quant à la manière dont le compilateur traite / utilise les constantes, il utilisera la valeur calculée à la place du nom de la constante dans le code.

Vous avez donc l'effet suivant:

  • Aucune référence au nom de la constante d'origine, à la classe dans laquelle elle a été déclarée ni à l'espace de nom n'est compilée dans le code à cet emplacement
  • Si vous décompilez le code, il contiendra des nombres magiques, simplement parce que la "référence" d'origine à la constante est, comme mentionné ci-dessus, pas présent, seule la valeur de la constante
  • Le compilateur peut utiliser cela pour optimiser, voire supprimer, le code inutile. Par exemple, if (SomeClass.Version == 1) , lorsque SomeClass.Version a la valeur 1, supprimera en fait l'instruction if et conservera le bloc de code en cours d'exécution. Si la valeur de la constante n'est pas 1, alors toute l'instruction if et son bloc seront supprimés.
  • Etant donné que la valeur d'une constante est compilée dans le code, et non une référence à la constante, l'utilisation de constantes d'autres assemblys ne mettra pas automatiquement à jour le code compilé si la valeur de la constante devait changer (ce qui devrait être le cas). non!)

En d'autres termes, dans le scénario suivant:

  1. L'assembly A contient une constante nommée "Version", ayant la valeur 1
  2. Assembly B contient une expression qui analyse le numéro de version de l'assembly A à partir de cette constante et le compare à 1 pour s'assurer qu'il peut fonctionner avec l'assembly
  3. Quelqu'un modifie l'assemblage A en augmentant la valeur de la constante à 2 et reconstruit A (mais pas B)

Dans ce cas, l'assemblage B, dans sa forme compilée, comparera toujours la valeur de 1 à 1, car lors de la compilation de B, la constante avait la valeur 1.

En fait, si tel est le seul usage de l'assemblage A de l'assemblage B, l'assemblage B sera compilé sans dépendance vis-à-vis de l'assembly A. L'exécution du code contenant cette expression dans l'assembly B ne chargera pas l'assembly A.

Les constantes ne doivent donc être utilisées que pour des choses qui ne changeront jamais. S'il s'agit d'une valeur susceptible de changer dans le futur et que vous ne pouvez pas garantir que tous les autres assemblages seront reconstruits simultanément, un champ en lecture seule est plus approprié qu'une constante.

Donc ça va:

  • public const Int32 NumberOfDaysInAWeekInGregorianCalendar = 7;
  • const public Int32 NumberOfHoursInADayOnEarth = 24;

alors que cela

Autres conseils

  

Quelqu'un at-il une théorie sur la raison de cette limitation?

S'il est permis que ce soit juste une théorie, ma théorie est que les valeurs const des types primitifs peuvent être exprimées à l'aide de paramètres d'opcode littéraux dans MSIL ... mais les valeurs d'autres types non primitifs ne le peuvent pas, car MSIL ne le permet pas. t ont la syntaxe pour exprimer la valeur d’un type défini par l’utilisateur sous forme littérale.

  

Je pense que le concept de const est en fait un sucre syntaxique en C #, et qu'il ne fait que remplacer toute utilisation du nom par la valeur littérale

Que fait le compilateur avec les objets const dans d'autres langages?

Vous pouvez utiliser readonly pour les types mutables qui doivent être évalués au moment de l'exécution. Voir cet article pour connaître les différences.

Les constantes

sont limitées aux nombres et aux chaînes en C # car le compilateur remplace la variable par la valeur littérale dans le fichier MSIL. En d'autres termes, lorsque vous écrivez:

const string myName = "Bruce Wayne";
if (someVar == myName)
{
   ...
}

est en fait traité comme

if (someVar == "Bruce Wayne")
{
   ...
}

et oui, le compilateur C # est assez intelligent pour traiter l'opérateur d'égalité (==) sur les chaînes comme

string1.Equals(string2)

Il me semble que seuls les types de valeur peuvent être exprimés sous forme de constante (à l'exception des chaînes, qui se situent quelque part entre le type valeur et le type d'objet).

Cela me convient: les objets (références) doivent être alloués sur le tas mais les constantes ne sont pas allouées du tout (puisqu'elles ont été remplacées à la compilation).

En résumé, tous les types simples, énumérations et chaînes sont immuables, mais pas l’instance Struct. Vous pouvez avoir une structure avec un état mutable (champs, propriétés, voire références aux types de référence). Le compilateur ne peut donc pas s’assurer (au moment de la compilation) que l’état interne d’une variable Struct ne peut pas être modifié. Le compilateur doit donc être sûr qu'un type est par définition immuable pour être utilisé dans une expression constante.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top