Impossible d'utiliser String.Empty comme valeur par défaut pour un paramètre facultatif

89

Je lis Effective C # de Bill Wagner. Dans l' élément 14 - Minimiser la logique d'initialisation en double , il montre l'exemple suivant d'utilisation de la nouvelle fonctionnalité de paramètres facultatifs dans un constructeur:

public MyClass(int initialCount = 0, string name = "")

Notez qu'il a utilisé à la ""place de string.Empty.
Il commente:

Vous noterez [dans un exemple ci-dessus] que le deuxième constructeur a spécifié "" pour la valeur par défaut sur le paramètre de nom , plutôt que la plus habituelle string.Empty. C'est parce que ce string.Emptyn'est pas une constante de compilation. C'est une propriété statique définie dans la classe de chaînes. Étant donné qu'il ne s'agit pas d'une constante de compilation, vous ne pouvez pas l'utiliser pour la valeur par défaut d'un paramètre.

Si nous ne pouvons pas utiliser la string.Emptystatique dans toutes les situations, cela ne va-t-il pas à l'encontre de son objectif? J'ai pensé que nous l'utiliserions pour être sûrs d'avoir un moyen indépendant du système de faire référence à la chaîne vide. Ma compréhension est-elle erronée? Merci.

MISE
À JOUR Juste un commentaire de suivi. Selon MSDN:

Chaque paramètre facultatif a une valeur par défaut dans le cadre de sa définition. Si aucun argument n'est envoyé pour ce paramètre, la valeur par défaut est utilisée. Les valeurs par défaut doivent être des constantes.

Ensuite, nous ne pouvons pas utiliser System.Environment.NewLineni l'un ni l'autre, ni utiliser des objets nouvellement instanciés comme valeurs par défaut. Je n'ai pas encore utilisé VS2010, et c'est décevant!

Mikeyg36
la source
2
Je n'ai connaissance d'aucune différence entre la façon dont les chaînes vides sont représentées sur différentes plates-formes. Ce n'est pas comme une nouvelle ligne.
Tom Cabanski
Bon, je pensais ça, alors est-ce juste que ça a l'air plus joli dans le code?
Mikeyg36
1
Le CLR et non le «système» est le facteur déterminant pour savoir si "" est une chaîne vide ou non. Je pense donc que vous pouvez supposer que le "" est une manière indépendante du système de désigner une chaîne sur une implémentation CLR conforme.
Chris Taylor
"indépendant du système"? euh, par opposition au "" spécifique au système? (???)
Qwertie
Selon MSDN: la valeur de ce champ est la chaîne de longueur nulle, "". alors cela n'a évidemment rien à voir avec l'indépendance de la plateforme, comme beaucoup de gens le soulignent. Pourtant, il semble toujours que les gens ne savent pas vraiment pourquoi il devrait être utilisé!
Mikeyg36

Réponses:

65

À partir du compilateur C # 2.0, il y a très peu d'intérêt de String.Emptytoute façon, et en fait, dans de nombreux cas, c'est une pessimisation, puisque le compilateur peut intégrer certaines références à ""mais ne peut pas faire de même avec String.Empty.

En C # 1.1, il était utile d'éviter de créer de nombreux objets indépendants contenant tous la chaîne vide, mais ces jours sont révolus. ""fonctionne très bien.

Andy Mortimer
la source
7
Même dans .NET 1.1, il ne créerait pas "beaucoup" d'objets indépendants. Je ne me souviens pas des détails des différences entre 1.1 et 2.0 à cet égard, mais ce n'est pas comme si l'internation littérale de chaîne n'avait été introduite que dans 2.0.
Jon Skeet
Merci pour la clarification. J'ai jeté un coup d'œil et je n'ai pas trouvé de bon résumé des changements dans C # 2.0, même si je suis sûr que j'en ai lu un auparavant. J'ai trouvé une réponse StackOverflow de 2008 avec des liens vers des informations plus techniques. stackoverflow.com/questions/151472/…
Andy Mortimer
1
Je vais faire un signe de tête, même si je n'aime pas dire qu'il n'y a pas grand chose à faire de la chaîne. Vide car je l'utilise assez fortement. Je trouve que ça a l'air plus propre, même si c'est mon opinion personnelle. Il y a beaucoup d'endroits string.Empty ne peut pas être utilisé, et je n'ai aucun problème à utiliser "" dans ces cas
xximjasonxx
14
J'ai trouvé qu'il est beaucoup plus facile d'identifier rapidement une chaîne vide avec String.Empty que de regarder deux fois "" pour s'assurer qu'il n'y avait pas d'apostrophe ou quelque chose comme ça caché. +1 pour l'explication cependant.
NotMe
11
+1 Chris. De plus, dans VS, vous ne pouvez vraiment pas faire de recherche sur les utilisations de "" (à part faire la recherche standard qui ramènera également chaque correspondance de texte, y compris les commentaires et le balisage). Vous pouvez effectuer une recherche sur les utilisations spécifiques du code avec string.Empty.
MutantNinjaCodeMonkey
53

Rien ne vous empêche de définir votre propre constante pour la chaîne vide si vous voulez vraiment l'utiliser comme valeur de paramètre facultative:

const string String_Empty = "";

public static void PrintString(string s = String_Empty)
{
    Console.WriteLine(s);
}

[En aparté, l' une des raisons de préférer String.Emptyplus ""en général, qui n'a pas été mentionné dans les autres réponses, est qu'il ya différents caractères Unicode (joiners zéro largeur, etc.) qui sont effectivement invisibles à l'œil nu. Donc, quelque chose qui ressemble ""n'est pas nécessairement la chaîne vide, alors qu'avec String.Emptyvous savez exactement ce que vous utilisez. Je reconnais que ce n'est pas une source courante de bogues, mais c'est possible.]

Matthew Strawbridge
la source
2
Il y a aussi des caractères d'identification invisibles, donc quelque chose qui ressemble à String_Empty n'est pas nécessairement. La norme Unicode contient un chapitre largement ignoré sur les considérations de sécurité.
Jim Balter
25

De la question d'origine:

J'ai pensé que nous l'utiliserions pour être sûrs d'avoir un moyen indépendant du système de faire référence à la chaîne vide.

De quelle manière la chaîne vide peut-elle varier d'un système à l'autre? C'est toujours une chaîne sans caractères! J'aurais vraiment peur si jamais je trouvais une implémentation string.Empty == ""retournée false :) Ce n'est pas la même chose que quelque chose comme Environment.NewLine.

Extrait du message sur les primes de Counter Terrorist:

Je veux String.Empty peut être utilisé comme paramètre par défaut dans la prochaine version C #. :RÉ

Eh bien, cela n'arrivera certainement pas.

Bien que j'aurais personnellement aimé un mécanisme par défaut très différent aussi, la façon dont les paramètres optionnels fonctionnent est dans .NET depuis le début - et cela signifie toujours incorporer une constante dans les métadonnées, afin que le code appelant puisse copier cette constante dans l'appel site si aucun argument correspondant n'est fourni.

Avec string.Emptyc'est vraiment inutile - utiliser ""fera ce que vous voulez; est-ce si pénible d'utiliser la chaîne littérale? (J'utilise le littéral partout - je n'utilise jamais string.Empty- mais c'est un argument différent.)

C'est ce qui me surprend dans cette question - la plainte tourne autour de quelque chose qui ne pose pas vraiment de problème. C'est plus important dans les cas où vous souhaitez que la valeur par défaut soit calculée au moment de l'exécution, car elle peut en fait varier. Par exemple, je pourrais imaginer des cas où vous souhaitez pouvoir appeler une méthode avec un DateTimeparamètre et la définir par défaut sur "l'heure actuelle". Pour le moment, la seule solution de contournement vaguement élégante que je connaisse est:

public void RecordTime(string message, DateTime? dateTime = null)
{
    var realDateTime = dateTime ?? DateTime.UtcNow;
}

... mais ce n'est pas toujours approprié.

En conclusion:

  • Je doute fort que cela fasse jamais partie de C #
  • Car string.Emptyc'est inutile de toute façon
  • Pour d'autres valeurs qui n'ont vraiment pas toujours la même valeur, cela peut vraiment être pénible
Jon Skeet
la source
C'est en fait un bon moyen de résoudre le problème. La même chose peut être utilisée pour transporter / définir d'autres variables dépendantes du périphérique telles que Environment.Newline.. La seule chose qui manque dans votre exemple serait une vérification de la variable pour null, et renvoyer une exception au développeur lui disant que même si elle est nullable, c'est pas accepté. if(dateTime == null){ throw new ArgumentException("The dateTime parameter must be set. Nullable type used for device independent variable set.");}ou quelque chose comme ça. Mais j'aime vraiment ça! Y a-t-il d'autres mises en garde pour le faire à votre façon?
MaxOvrdrv
@MaxOvrdrv: Vous ne voulez pas que la valeur null soit une erreur - le point essentiel est que lorsqu'elle est nulle, vous calculez une valeur par défaut. La mise en garde est qu'elle n'autorise pas le passage de null en tant que valeur valide en soi.
Jon Skeet
Vous avez tout à fait raison à ce sujet. Ma faute. - Et oui, ce serait la seule vraie mise en garde n'est-ce pas… ce n'est pas trop mal. Encore une fois: j'aime vraiment cette solution! :) Merci de l'avoir posté! :)
MaxOvrdrv
7

Je n'utilise jamais de chaîne, vide, je n'en vois pas l'intérêt. Peut-être que cela facilite les choses pour les personnes qui sont vraiment novices en programmation, mais je doute que ce soit utile même pour cela.

Hans Olsson
la source
2
Peut-être que cela évite la confusion ""et " ", mais je ne peux pas dire que " "c'est si courant.
Greg
8
Je suggérerais que quiconque ne peut pas faire la différence entre ces besoins ait besoin de meilleures lunettes ou de réduire la résolution de son écran. J'ai une mauvaise vue et je ne me souviens pas d'avoir fait cette erreur (et je dois travailler avec beaucoup de code qui contient les deux).
Hans Olsson
2
string.Empty est utile pour connaître l'intention exacte du programmeur. "" ne dit rien sur l'intention, que se passe-t-il si l'intention du programmeur était d'initialiser la variable comme ceci "lol" mais oubliée ... dans ce cas, les possibilités et la chaîne sont infinies, Empty est pratique et fait un meilleur travail
utileBee
4

Je pense que l'idée derrière string.Empty est qu'elle améliore la lisibilité. Ce n'est pas comme une nouvelle ligne où il y a une différence entre la façon dont elle est représentée sur différentes plates-formes. C'est dommage qu'il ne puisse pas être utilisé dans un paramètre par défaut. Cependant, cela ne posera aucun problème si vous portez entre Windows et quelque chose comme Mono sous Linux.

Tom Cabanski
la source
5
Je pense que vous avez probablement raison de dire que le fait est que certaines personnes considèrent String.Emptyplus lisible. . . personnellement cependant, je pense que c'est un peu dingue. ""est probablement la chaîne la plus courante et tout le monde l'a vue un milliard de fois, alors comment est-elle illisible? String.Emptyest à peu près aussi utile que s'il y avait un fichier Int32.Zero.
Tim Goodman
3

En tant que FYI, il semble que la même contrainte soit imposée aux valeurs transmises aux constructeurs d'attributs - elles doivent être constantes. Puisque string.empty est défini comme:

public static readonly string Empty

plutôt qu'une constante réelle, elle ne peut pas être utilisée.

Shawn Eavis
la source
1

J'utilise string.Emptyuniquement pour la lisibilité.

Si quelqu'un d'autre a besoin de lire / modifier mon code plus tard, il sait que je voulais vérifier ou définir quelque chose sur une chaîne vide. Utiliser juste ""peut parfois causer des bugs et de la confusion parce que j'ai peut-être oublié de mettre la chaîne que je voulais.

Par exemple:

if(someString == string.Empty)
{

}

contre

if(someString == "")
{

}

La première ifdéclaration me semble tellement plus délibérée et lisible. Parce que ce n'est qu'une préférence cependant, je ne vois vraiment pas le train-smash d'avoir à utiliser ""au lieu de string.Empty.

lukejkw
la source
-2

La meilleure solution à ce problème est peut-être une surcharge de cette méthode, de cette manière:

public static void PrintString() 
{ 
    PrintString(string.Empty);
}
lokum09
la source
3
Comment cela répond à la question ci-dessus?
Pranav Singh
1
Comment cela aide-t-il avec les valeurs par défaut des paramètres facultatifs?
locale par défaut le