C'est assez ennuyeux de tester toutes mes chaînes null
avant de pouvoir appliquer en toute sécurité des méthodes comme ToUpper()
, StartWith()
etc ...
Si la valeur par défaut de string
était la chaîne vide, je n'aurais pas à tester et je la sentirais plus cohérente avec les autres types de valeur comme int
ou double
par exemple. De plus, cela Nullable<String>
aurait du sens.
Alors pourquoi les concepteurs de C # ont-ils choisi d'utiliser null
comme valeur par défaut des chaînes?
Remarque: Cela se rapporte à cette question , mais est plus axé sur le pourquoi plutôt que sur ce qu'il faut en faire.
c#
string
default-value
Marcel
la source
la source
null
(et je vous recommande également de traiter conceptuellementnull
et de vider les chaînes comme des choses différentes). Une valeur nulle peut être le résultat d'une erreur quelque part, tandis qu'une chaîne vide doit transmettre une signification différente.Réponses:
Car
string
est un type de référence et la valeur par défaut pour tous les types de référence estnull
.Cela est cohérent avec le comportement des types de référence. Avant d'appeler leurs membres d'instance, il convient de mettre en place une vérification pour une référence nulle.
Affecter la valeur par défaut à un type de référence spécifique autre que
null
le rendrait incohérent .Nullable<T>
fonctionne avec les types de valeur. Il convient de noter le fait qu'ilNullable
n'a pas été introduit sur la plate-forme .NET d' origine, il y aurait donc eu beaucoup de code cassé s'ils avaient modifié cette règle. ( Courtesy @jcolebrand )la source
String
, à l'exception de (1) le comportement value-type-ish d'avoir une valeur par défaut utilisable, et (2) une couche supplémentaire malheureuse d'indirection de boxe à chaque fois qu'il est converti enObject
. Étant donné que la représentation en tas destring
est unique, avoir un traitement spécial pour éviter la boxe supplémentaire n'aurait pas été très difficile (en fait, être capable de spécifier des comportements de boxe non par défaut serait également une bonne chose pour d'autres types).Habib a raison - car
string
c'est un type de référence.Mais plus important encore, vous n'avez pas à vérifier
null
chaque fois que vous l'utilisez. Vous devriez probablement jeter unArgumentNullException
si quelqu'un transmet unenull
référence à votre fonction .Voici la chose - le framework vous lancerait
NullReferenceException
de toute façon si vous essayiez d'appeler.ToUpper()
une chaîne. N'oubliez pas que ce cas peut toujours se produire même si vous testez vos argumentsnull
car toute propriété ou méthode sur les objets passés à votre fonction en tant que paramètres peut être évaluée commenull
.Cela étant dit, la vérification des chaînes vides ou des valeurs nulles est une chose courante à faire, donc elles fournissent
String.IsNullOrEmpty()
etString.IsNullOrWhiteSpace()
à cette fin.la source
NullReferenceException
vous - même ( msdn.microsoft.com/en-us/library/ms173163.aspx ); vous lancez unArgumentNullException
si votre méthode ne peut pas accepter de références nulles. De plus, les NullRef sont généralement l'une des exceptions les plus difficiles aux diagnostics lorsque vous résolvez des problèmes, donc je ne pense pas que la recommandation de ne pas vérifier la valeur null soit très bonne.ArgumentNullException
a l'avantage supplémentaire de pouvoir fournir le nom du paramètre. Pendant le débogage, cela économise ... euh, secondes. Mais des secondes importantes.Vous pouvez écrire une méthode d'extension (pour ce qu'elle vaut):
Maintenant, cela fonctionne en toute sécurité:
la source
.EmptyNull()
, pourquoi ne pas simplement utiliser à la(str ?? "")
place là où vous en avez besoin? Cela dit, je suis d'accord avec le sentiment exprimé dans le commentaire de @ DaveMarkle: vous ne devriez probablement pas.null
etString.Empty
sont conceptuellement différents, et vous ne pouvez pas nécessairement traiter l'un de la même manière qu'un autre.Vous pouvez également utiliser ce qui suit, à partir de C # 6.0
Le résultat de la chaîne sera nul.
la source
public string Name { get; set; } = string.Empty;
Les chaînes vides et les valeurs nulles sont fondamentalement différentes. Un null est une absence de valeur et une chaîne vide est une valeur qui est vide.
Le langage de programmation faisant des hypothèses sur la "valeur" d'une variable, dans ce cas une chaîne vide, sera aussi efficace que d'initier la chaîne avec toute autre valeur qui ne causera pas de problème de référence nulle.
De plus, si vous passez le handle de cette variable de chaîne à d'autres parties de l'application, ce code n'aura aucun moyen de valider si vous avez intentionnellement passé une valeur vide ou si vous avez oublié de remplir la valeur de cette variable.
Une autre occasion où ce serait un problème est lorsque la chaîne est une valeur de retour d'une fonction. Étant donné que la chaîne est un type de référence et peut techniquement avoir une valeur nulle et vide à la fois, par conséquent, la fonction peut également retourner techniquement un null ou un vide (rien ne l'empêche de le faire). Maintenant, comme il y a 2 notions d '"absence de valeur", c'est-à-dire une chaîne vide et une valeur nulle, tout le code qui consomme cette fonction devra faire 2 vérifications. Un pour vide et l'autre pour null.
En bref, il est toujours bon de n'avoir qu'une seule représentation pour un seul état. Pour une discussion plus large sur les vides et les null, voir les liens ci-dessous.
/software/32578/sql-empty-string-vs-null-value
NULL vs vide en cas de saisie utilisateur
la source
null
pour représenter la chaîne vide. Il y avait un certain nombre de façons dont .net aurait pu implémenter une sémantique similaire, s'il avait choisi de le faire, d'autant plus qu'ilString
possède un certain nombre de caractéristiques qui en font de toute façon un type unique [par exemple, il et les deux types de tableaux sont les seuls types dont l'allocation la taille n'est pas constante].La raison / le problème fondamental est que les concepteurs de la spécification CLS (qui définit comment les langues interagissent avec .net) n'ont pas défini de moyen par lequel les membres de la classe pourraient spécifier qu'ils doivent être appelés directement, plutôt que via
callvirt
, sans que l'appelant effectue une vérification de référence nulle; elle n'a pas non plus permis de définir des structures qui ne seraient pas soumises à une boxe "normale".Si la spécification CLS avait défini un tel moyen, il serait alors possible pour .net de suivre systématiquement l'exemple établi par le Common Object Model (COM), selon lequel une référence de chaîne nulle était considérée sémantiquement équivalente à une chaîne vide, et pour d'autres types de classes immuables définis par l'utilisateur qui sont censés avoir une sémantique de valeurs pour définir également des valeurs par défaut. Essentiellement, ce qui se passerait serait que chaque membre de
String
, par exemple,Length
soit écrit comme quelque chose comme[InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }
. Cette approche aurait offert une très bonne sémantique pour les choses qui devraient se comporter comme des valeurs, mais en raison des problèmes d'implémentation, elles doivent être stockées sur le tas. La plus grande difficulté avec cette approche est que la sémantique de conversion entre ces types etObject
pourrait devenir un peu trouble.Une approche alternative aurait été de permettre la définition de types de structure spéciaux qui n'héritent pas
Object
mais qui ont à la place des opérations de boxe et de déballage personnalisées (qui se convertissent vers / depuis un autre type de classe). Dans une telle approche, il y aurait un type de classeNullableString
qui se comporte comme une chaîne maintenant, et un type de structure encadré personnaliséString
, qui contiendrait un seul champ privéValue
de typeString
. Tentative de conversionString
de aNullableString
ouObject
retourneValue
si non-null ouString.Empty
si null. En tentant de transtyper enString
, une référence non nulle à uneNullableString
instance stockerait la référence dansValue
(peut-être en stockant null si la longueur était nulle); le fait de jeter toute autre référence entraînerait une exception.Même si les chaînes doivent être stockées sur le tas, il n'y a théoriquement aucune raison pour qu'elles ne se comportent pas comme des types de valeur qui ont une valeur par défaut non nulle. Les avoir stockés comme une structure "normale" qui contenait une référence aurait été efficace pour le code qui les utilisait comme type "chaîne", mais aurait ajouté une couche supplémentaire d'indirection et d'inefficacité lors de la conversion en "objet". Bien que je ne prévois pas .net d'ajouter l'une des fonctionnalités ci-dessus à cette date tardive, les concepteurs de futurs cadres pourraient peut-être envisager de les inclure.
la source
Nullable<>
, les chaînes peuvent être réimplémentées en tant que types de valeur; Je ne peux pas parler des coûts et des avantages d'un tel choix.string
est plus efficace qu'ilNullable<string>
ne le serait, avoir à utiliser la méthode "plus efficace" est plus contraignant que de pouvoir utiliser la même approche pour toutes les valeurs de base de données annulables.Parce qu'une variable de chaîne est une référence , pas une instance .
L'initialiser à Vide par défaut aurait été possible mais cela aurait introduit beaucoup d'incohérences sur toute la carte.
la source
string
devoir être un type de référence. Bien sûr, les caractères réels qui composent la chaîne doivent certainement être stockés sur le tas, mais étant donné la quantité de support dédié que les chaînes ont déjà dans le CLR, il ne serait pas étirable d'avoirSystem.String
un type de valeur avec un champ privé uniqueValue
de typeHeapString
. Ce champ serait un type de référence et aurait la valeur par défautnull
, mais uneString
structure dont leValue
champ était nul se comporterait comme une chaîne vide. Le seul inconvénient de cette approche serait ...String
toObject
entraînerait, en l'absence de code de cas particulier lors de l'exécution, la création d'uneString
instance encadrée sur le tas, plutôt que de simplement copier une référence auHeapString
..Length
etc. de sorte que les instances qui détiennent une référence nulle n'essaierait pas de le déréférencer mais se comporterait à la place comme approprié pour une chaîne vide. Si le Framework serait meilleur ou pire avec unestring
implémentation de cette façon, si l'on voulaitdefault(string)
être une chaîne vide ...string
un wrapper de type valeur sur un champ de type référence serait l'approche qui nécessiterait le moins de modifications dans les autres parties de .net [en effet, si l'on était prêt à accepter la conversion deString
pourObject
créer un élément supplémentaire, on aurait pu simplementString
être une structure ordinaire avec un champ de typeChar[]
qu'elle n'a jamais exposé]. Je pense qu'avoir unHeapString
type serait probablement mieux, mais à certains égards, la chaîne de type valeur contenant unChar[]
serait plus simple.Étant donné que les chaînes sont des types de référence , les types de référence sont la valeur par défaut est
null
. Les variables des types de référence stockent des références aux données réelles.Utilisons un
default
mot-clé pour ce cas;str
est unstring
, donc c'est un type de référence , donc la valeur par défaut estnull
.str
est unint
, c'est donc un type de valeur , donc la valeur par défaut estzero
.la source
Faux! La modification de la valeur par défaut ne change pas le fait qu'il s'agit d'un type de référence et que quelqu'un peut toujours définir explicitement la référence comme étant
null
.Vrai point. Il serait plus logique de ne pas autoriser
null
de types de référence, au lieu d'exigerNullable<TheRefType>
cette fonctionnalité.Cohérence avec d'autres types de référence. Maintenant, pourquoi autoriser
null
les types de référence? Probablement pour qu'il ressemble à C, même si c'est une décision de conception discutable dans un langage qui fournit égalementNullable
.la source
Peut-être que si vous utilisiez l'
??
opérateur lors de l'attribution de votre variable de chaîne, cela pourrait vous aider.la source
Une chaîne est un objet immuable, ce qui signifie que lorsqu'elle reçoit une valeur, l'ancienne valeur n'est pas effacée de la mémoire, mais reste à l'ancien emplacement et la nouvelle valeur est placée dans un nouvel emplacement. Donc, si la valeur par défaut de
String a
étaitString.Empty
, cela gaspillerait laString.Empty
bloc en mémoire quand on sa première valeur.Bien que cela semble minuscule, cela pourrait devenir un problème lors de l'initialisation d'un grand tableau de chaînes avec des valeurs par défaut de
String.Empty
. Bien sûr, vous pouvez toujours utiliser laStringBuilder
classe mutable si cela devait être un problème.la source
String.Empty
. Suis-je trompé?string
soit une chaîne vide est d'autoriser tous les bits à zéro comme représentation d'une chaîne vide. Il y a plusieurs façons d'y parvenir, mais je ne pense pas que cela implique d'initialiser les références àString.Empty
.String.Empty
ou""
.string
emplacements de stockage aurait nécessité également de changer le comportement d'initialisation de toutes les structures ou classes qui ont des champs de typestring
. Cela représenterait un assez grand changement dans la conception de .net, qui prévoit actuellement d'initialiser à zéro n'importe quel type sans même avoir à penser à ce qu'il est, sauf pour sa taille totale.La chaîne étant un type de référence et la valeur par défaut du type de référence est null.
la source
Peut-être que le
string
mot clé vous a dérouté, car il ressemble exactement à toute autre déclaration de type de valeur , mais il s'agit en fait d'un aliasSystem.String
comme expliqué dans cette question .De plus, la couleur bleu foncé dans Visual Studio et la première lettre minuscule peuvent induire en erreur en pensant qu'il s'agit d'un
struct
.la source
object
mot clé? Certes, c'est beaucoup moins utilisé questring
.int
c'est un alias pourSystem.Int32
. À quoi veux-tu en venir? :)System.Int32
c'estStruct
donc un ayant une valeur par défaut tandisSystem.String
qu'un aClass
un pointeur avec une valeur par défaut denull
. Ils sont visuellement présentés dans la même police / couleur. Sans connaissance, on peut penser qu'ils agissent de la même manière (= avoir une valeur par défaut). Ma réponse a été écrite avec une idée de psychologie cognitive en.wikipedia.org/wiki/Cognitive_psychology derrière elle :-)Les types nullables ne sont entrés qu'en 2.0.
Si des types nullables avaient été créés au début du langage, alors la chaîne aurait été non nullable et la chaîne? aurait été annulable. Mais ils ne pouvaient pas faire cela du à la compatibilité descendante.
Beaucoup de gens parlent de type ref ou non de type ref, mais la chaîne est une classe hors du commun et des solutions auraient été trouvées pour le rendre possible.
la source