Pourquoi String.Empty n'est-il pas une constante?


189

Dans .Net, pourquoi String.Empty est-il en lecture seule au lieu d'une constante? Je me demande simplement si quelqu'un sait quel était le raisonnement derrière cette décision.


5
Cette question peut résoudre celle-ci, la réponse brève est, personne ne le sait ...
gdoron soutient Monica

Ouais, +1 pour la réponse d'Eric Lippert, merci!
travis

Surtout étant donné que Decimal.Zero est const (du point de vue de l'utilisateur, c'est-à-dire ...)
Hamish Grubijan

Réponses:


149

La raison qui static readonlyest utilisée à la place de constest due à une utilisation avec du code non managé, comme indiqué par Microsoft ici dans la version Shared Source Common Language Infrastructure 2.0 . Le fichier à consulter est sscli20\clr\src\bcl\system\string.cs.

La constante Empty contient la valeur de chaîne vide. Nous devons appeler le constructeur String afin que le compilateur ne le marque pas comme un littéral.

Marquer cela comme un littéral signifierait qu'il n'apparaît pas comme un champ auquel nous pouvons accéder à partir de natif.

J'ai trouvé ces informations dans cet article pratique sur CodeProject .


J'apprécierais vraiment si vous pouviez expliquer ce commentaire (parce que Jon Skeet ne pouvait pas ...) voir ici: stackoverflow.com/questions/8462697
...

2
@gdoron: Ma supposition (et c'est une supposition) est la suivante. Lorsqu'une valeur est définie comme un littéral (une constante), sa valeur est insérée aux endroits où elle est référencée tandis que lorsqu'elle n'est pas définie comme un littéral, la source de la valeur est référencée et la valeur réelle est récupérée lors de l'exécution. Je soupçonne que ce dernier peut garantir qu'un bon marshalling de la chaîne se produit entre natif et .NET au moment de l'exécution - s'il s'agissait d'un littéral, le compilateur natif aurait peut-être besoin de tirer la valeur littérale dans son code natif, ce qui n'est probablement pas réalisable. Mais ce n’est que des conjectures de ma part.
Jeff Yates

7
Cela signifie qu'il faut utiliser "", plutôt que string.Empty pour les valeurs de paramètre par défaut dans les méthodes. Ce qui est légèrement ennuyeux.
nicodemus13

17
"" peut ressembler à une erreur, tandis que string.Empty montre une intention délibérée
Christopher Stevenson

3
@JeffYates J'ajouterais que le fait que ce ne soit pas cohérent est déjà ennuyeux. Les gens verraient le reste du code et se demanderaient "pourquoi utilise-t-il" "ici au lieu de String.Empty?". J'envisage sérieusement de ne String.Emptyplus utiliser pour cette seule raison.
julealgon

24

Je pense qu'il y a beaucoup de confusion et de mauvaises réponses ici.

Tout d'abord, les constchamps sont des staticmembres ( pas des membres d'instance ).

Consultez la section 10.4 Constantes de la spécification du langage C #.

Même si les constantes sont considérées comme des membres statiques, une déclaration de constante ne nécessite ni n'autorise un modificateur statique.

Si les public constmembres sont statiques, on ne peut pas considérer qu'une constante créera un nouvel objet.

Compte tenu de cela, les lignes de code suivantes font exactement la même chose en ce qui concerne la création d'un nouvel objet.

public static readonly string Empty = "";
public const string Empty = "";

Voici une note de Microsoft qui explique la différence entre les 2:

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 en lecture seule peut être initialisé au niveau de la déclaration ou dans un constructeur. Par conséquent, les champs en lecture seule peuvent avoir des valeurs différentes selon le constructeur utilisé. De plus, alors qu'un champ const est une constante de compilation, le champ readonly peut être utilisé pour les constantes d'exécution, ...

Je trouve donc que la seule réponse plausible ici est celle de Jeff Yates.


+1 pour les mots aimables et la clarification concernant la spécification C # sur const et statique en lecture seule.
Jeff Yates

17
En relisant ceci, je ne suis pas d'accord const stringet static readonly stringje fais la même chose. Les valeurs const sont remplacées dans le code lié tandis que les valeurs statiques en lecture seule sont référencées. Si vous avez un constdans la bibliothèque A qui est utilisé par la bibliothèque B, la bibliothèque B remplacera toutes les références à cette constvariable par sa valeur littérale; si cette variable l'était à la static readonlyplace, elle serait référencée et sa valeur déterminée au moment de l'exécution.
Jeff Yates

3
Le point de Jeff est important lors du référencement des bibliothèques. Si vous recompilez A et le redistribuez, sans recompiler B , B utilisera toujours les anciennes valeurs.
Mark Sowul

5
String.Empty read only instead of a constant?

Si vous rendez une chaîne constante , le compilateur est remplacé par la chaîne en fait partout où vous l'appelez et vous remplissez votre code avec la même chaîne partout et lorsque le code s'exécute, il est également nécessaire de lire encore et encore cette chaîne à partir de la mémoire différente Les données.

Si vous laissez votre chaîne en lecture seule à un seul endroit comme c'est le cas String.Empty, le programme ne conserve la même chaîne qu'à un seul endroit et la lit ou y fait référence - en gardant les données en mémoire au minimum.

De plus, si vous compilez une dll en utilisant le String.Empty comme const, et pour une raison quelconque le changement de String.Empty, alors la dll compilée ne fonctionnera plus de la même manière, car le costcode interne permet de conserver une copie de la chaîne à chaque appel.

Voir ce code par exemple:

public class OneName
{
    const string cConst = "constant string";
    static string cStatic = "static string";
    readonly string cReadOnly = "read only string";

    protected void Fun()
    {
        string cAddThemAll ;

        cAddThemAll = cConst;
        cAddThemAll = cStatic ;
        cAddThemAll = cReadOnly;    
    }
}

sera venu par le compilateur comme:

public class OneName
{
    // note that the const exist also here !
    private const string cConst = "constant string";
    private readonly string cReadOnly;
    private static string cStatic;

    static OneName()
    {
        cStatic = "static string";
    }

    public OneName()
    {
        this.cReadOnly = "read only string";
    }

    protected void Fun()
    {
        string cAddThemAll ;

        // look here, will replace the const string everywhere is finds it.
        cAddThemAll = "constant string";
        cAddThemAll = cStatic;
        // but the read only will only get it from "one place".
        cAddThemAll = this.cReadOnly;

    }
}

et l'appel à l'assemblée

        cAddThemAll = cConst;
0000003e  mov         eax,dword ptr ds:[09379C0Ch] 
00000044  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cStatic ;
00000047  mov         eax,dword ptr ds:[094E8C44h] 
0000004c  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cReadOnly;
0000004f  mov         eax,dword ptr [ebp-3Ch] 
00000052  mov         eax,dword ptr [eax+0000017Ch] 
00000058  mov         dword ptr [ebp-44h],eax 

Edit: faute de frappe corrigée


Donc, cela signifie que la chaîne const doit toujours être instanciée avec la classe contenant ce const? Cela semble alors préférable d'utiliser la lecture statique en lecture seule.
the berserker

@theberserker est bien mieux, mais vous avez toutes les options à utiliser.
Aristos

> alors la dll compilée ne fonctionnera plus de la même manière, car le coût oblige le code interne à conserver réellement une copie de la chaîne à chaque appel. @Aristos Ce n'est pas tout à fait vrai. Une fois le code compilé, la "copie" de la chaîne sera référencée dans le bloc TEXT de l'exécutable, et tout le code référencera simplement ce même bloc de mémoire. Ce que vous avez cité dans votre deuxième étape est simplement une étape intermédiaire.
Peter Dolkens

@ user1533523 merci pour la note - Je ferai un test quand je trouverai le temps de vérifier cela
Aristos

Comment avez-vous obtenu ce code d'assemblage? C # ne compile pas en assembleur!
jv110

0

Cette réponse existe à des fins historiques.

Initialement:

Parce que Stringc'est une classe et ne peut donc pas être une constante.

Discussion approfondie:

Un grand nombre de dialogues utiles ont été élaborés pour vérifier cette réponse, et plutôt que de la supprimer, ce contenu est reproduit directement:

Dans .NET, (contrairement à Java), la chaîne et la chaîne sont exactement les mêmes. Et oui, vous pouvez avoir des constantes littérales de chaîne dans .NET - DrJokepu 3 février 09 à 16:57

Êtes-vous en train de dire qu'une classe ne peut pas avoir de constantes? - StingyJack 3 février 09 à 16:58

Oui, les objets doivent être utilisés en lecture seule. Seules les structures peuvent faire des constantes. Je pense que lorsque vous utilisez à la stringplace du Stringcompilateur, vous changez le const en lecture seule pour vous. Tout à voir avec la satisfaction des programmeurs C. - Garry Shutler le 3 février 2009 à 16 h 59

tvanfosson vient de l'expliquer un peu plus verbeux. "X ne peut pas être une constante, car le Y contenant est une classe" était juste un peu trop sans contexte;) - Leonidas 3 février 09 à 17:01

string.Empty est une propriété statique qui renvoie une instance de la classe String, à savoir la chaîne vide, pas la classe chaîne elle-même. - tvanfosson le 3 février 2009 à 17:01

Empty est une instance en lecture seule (ce n'est pas une propriété) de la classe String. - senfo 3 février 09 à 17:02

Tête qui fait mal. Je pense toujours que j'ai raison, mais maintenant je suis moins sûr. Recherche requise ce soir! - Garry Shutler 3 février 2009 à 17:07

La chaîne vide est une instance de la classe de chaînes. Empty est un champ statique (pas une propriété, je suis corrigé) sur la classe String. Fondamentalement, la différence entre un pointeur et la chose vers laquelle il pointe. Si ce n'était pas en lecture seule, nous pourrions changer à quelle instance le champ Empty se réfère. - tvanfosson le 3 février 2009 à 17:07

Garry, tu n'as pas besoin de faire de recherches. Pensez-y. String est une classe. Empty est une instance d'une chaîne. - senfo le 3 février 09 à 17:12

Il y a quelque chose que je ne comprends pas tout à fait: comment diable le constructeur statique de la classe String peut-il créer une instance de la classe String? N'est-ce pas une sorte de scénario «poulet ou œuf»? - DrJokepu 3 février 09 à 17:12 5

Cette réponse serait correcte pour presque toutes les autres classes sauf System.String. .NET fait beaucoup de casse spéciale de performance pour les chaînes, et l'un d'eux est que vous POUVEZ avoir des constantes de chaîne, essayez-le. Dans ce cas, Jeff Yates a la bonne réponse. - Joel Mueller 3 février 09 à 19:25

Comme décrit au §7.18, une expression constante est une expression qui peut être entièrement évaluée au moment de la compilation. Étant donné que la seule façon de créer une valeur non nulle d'un type de référence autre que chaîne est d'appliquer le nouvel opérateur, et puisque le nouvel opérateur n'est pas autorisé dans une expression constante, la seule valeur possible pour les constantes de types référence autre que string est nul. Les deux commentaires précédents ont été tirés directement de la spécification du langage C # et réitèrent ce que Joel Mueller a mentionné. - senfo 4 février 09 à 15:05 5


Veuillez voter contre la bonne réponse. Si vous allez à la définition, vous constaterez qu'elle appartient à la classe String et est une instance de String. Le fait qu'il s'affiche en minuscules est la magie du compilateur.
Garry Shutler

Ce n'est pas moi qui vous ai critiqué, mais en .NET, (contrairement à Java), la chaîne et la chaîne sont exactement les mêmes. Et oui, vous pouvez avoir des constantes littérales de chaîne dans .NET
Tamas Czinege

10
Cette réponse serait correcte pour presque toutes les autres classes sauf System.String. .NET fait beaucoup de casse spéciale de performance pour les chaînes, et l'un d'eux est que vous POUVEZ avoir des constantes de chaîne, essayez-le. Dans ce cas, Jeff Yates a la bonne réponse.
Joel Mueller

7
J'ai presque supprimé cette réponse au fur et à mesure qu'une bien meilleure est arrivée, mais la discussion dans ces commentaires vaut la peine d'être conservée.
Garry Shutler le

1
@Garry, tu as de la chance d'avoir lu ton dernier commentaire, sinon je voterais aussi contre. Une chaîne a une fonctionnalité spéciale dans .NET, que si c'est une classe ref, cela peut être un const.
Shimmy Weitzhandler le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.