Initialisation de la chaîne par défaut: NULL ou vide? [fermé]

130

J'ai toujours initialisé mes chaînes à NULL, en pensant que NULL signifie l'absence d'une valeur et "" ou String.Empty est une valeur valide. J'ai vu plus d'exemples récemment de code où String.Empty est considéré comme la valeur par défaut ou ne représente aucune valeur. Cela me semble étrange, avec les types NULL nouvellement ajoutés dans c #, il semble que nous faisons des pas en arrière avec des chaînes en n'utilisant pas NULL pour représenter 'No Value'.

Qu'est-ce que vous utilisez comme initialiseur par défaut et pourquoi?

Edit: Sur la base des réponses, j'ai approfondi mes pensées

  1. Éviter la gestion des erreurs Si la valeur ne doit pas être nulle, pourquoi a-t-elle été définie NULLen premier lieu? Peut-être serait-il préférable d'identifier l'erreur à l'endroit où elle se produit plutôt que de la dissimuler dans le reste de votre base de code?

  2. Éviter les vérifications nulles Si vous êtes fatigué de faire des vérifications nulles dans le code, ne serait-il pas préférable d'abstraire les vérifications nulles? Peut-être envelopper (ou étendre!) Les méthodes de chaîne pour les rendre NULLsûres? Que se passe-t-il si vous utilisez constamment String.Emptyet qu'un null arrive à fonctionner dans votre système, commencez-vous quand même à ajouter des NULLvérifications?

Je ne peux m'empêcher de revenir sur l'opinion que c'est de la paresse. N'importe quel DBA vous giflerait de neuf façons stupides si vous utilisiez «» au lieu de nulldans sa base de données. Je pense que les mêmes principes s'appliquent à la programmation et qu'il devrait y avoir quelqu'un pour frapper ceux à l'envers qui utilisent String.Emptyplutôt que NULLde représenter aucune valeur.

questions connexes

vfilby
la source
«Le Sane»? Ce ne doit pas être un Dana que je connais.
vfilpar
@Joel, je suis étonné de voir combien de personnes n'ont aucune idée de Zim ou de GIR.Je suis également étonné de voir certains de mes amis qui trouvent cela répugnant. Je ne dis pas que c'est de la pure bonté, mais il y a des pépites d'humour impressionnantes.
vfilpar
Je sais, mais parfois c'est amusant de prétendre le contraire.
Dana the Sane
1
Je rencontre beaucoup ce problème sur les collections de formulaires MVC ou les variables de session, j'ai trouvé que la chose la plus utile était de convertir null en String.Empty avec le ?? raccourci, puis appliquez toute opération de chaîne requise. par exemple. (item ?? String.Empty) .Trim (). ToUpper ()
sonjz
4
ce n'est pas constructif ??
nawfal

Réponses:

111

+1 pour faire la distinction entre "vide" et NULL. Je conviens que «vide» doit signifier «valide, mais vide» et «NULL» doit signifier «invalide».

Je répondrais donc à votre question comme ceci:

vide lorsque je veux une valeur par défaut valide qui peut ou non être modifiée, par exemple, le deuxième prénom d'un utilisateur.

NULL lorsqu'il s'agit d'une erreur si le code qui s'ensuit ne définit pas la valeur explicitement.

Adam Liss
la source
11
La distinction entre NULL et vide est excellente quand il y a en fait une différence entre les deux. Il y a cependant de nombreux cas où il n'y a pas de différence, et donc avoir deux façons de représenter la même chose est un handicap.
Greg Smalter
6
@Greg: Bien que je convienne que la variété a un potentiel de confusion, elle peut aussi être un grand atout. La convention simple et cohérente d'écrire "" ou NULL pour différencier les valeurs valides et non valides rendra votre code plus facile à comprendre. C'est pourquoi je teste toujours les booléens avec "if (var)", les pointeurs avec "if (var! = NULL)" et les entiers avec "if (var! = 0)" - ils signifient tous la même chose pour le compilateur, mais ils contiennent des informations supplémentaires qui aident le pauvre développeur qui maintient mon code.
Adam Liss
32

Selon MSDN :

En initialisant les chaînes avec la Emptyvaleur au lieu de null, vous pouvez réduire les chances qu'un NullReferenceException.

Toujours utiliser IsNullOrEmpty()est néanmoins une bonne pratique.

Tomalak
la source
45
Ce n'est pas parce que vous réduisez les chances d'exception que l'exception ne devrait pas se produire. Si votre code dépend de la présence d'une valeur, il devrait lever une exception!
rmeador
1
Bien sûr, aucun argument ici. OTOH, si vous ajoutez simplement des chaînes ensemble ... Je pense que cela dépend du style de codage, de l'expérience et de la situation.
Tomalak
C'est principalement ce que j'utilise pour distinguer lequel utiliser également.
PositiveGuy
3
N'oubliez pas IsNullOrWhiteSpace () pour .NET Framework 4+
Coops
13

Pourquoi voulez-vous que votre chaîne soit initialisée? Vous n'avez pas besoin d'initialiser une variable lorsque vous en déclarez une, et IMO, vous ne devez le faire que lorsque la valeur que vous affectez est valide dans le contexte du bloc de code.

Je vois beaucoup ça:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else
{
  name = "bar";
}

return name;

Ne pas initialiser à null serait tout aussi efficace. De plus, le plus souvent, vous souhaitez qu'une valeur soit attribuée. En initialisant à null, vous pouvez potentiellement manquer des chemins de code qui n'affectent pas de valeur. Ainsi:

string name = null; // or String.Empty
if (condition)
{
  name = "foo";
}
else if (othercondition)
{
  name = "bar";
}

return name; //returns null when condition and othercondition are false

Lorsque vous n'initialisez pas à null, le compilateur génère une erreur indiquant que tous les chemins de code n'affectent pas de valeur. Bien sûr, ceci est un exemple très simple ...

Matthijs


la source
Dans Visual Studio, que je crois que presque tous les programmeurs C # utilisent, votre deuxième situation (sans le = null) générerait un avertissement, pour exactement la raison que vous avez indiquée - peu importe que la valeur par défaut d'une chaîne soit nulle. si vous ne garantissez pas une affectation à travers chaque chemin de code, l'EDI (et / ou je suppose que le compilateur sous-jacent [?]) générera un avertissement. Bien que les avertissements n'empêchent pas la compilation, ils sont toujours là - laisser ceux qui sont facilement résolus peut aider à masquer d'autres qui peuvent justifier l'attention du programmeur
Code Jockey
à ma connaissance, la première situation sera parfaitement satisfaite sans initialisation de nameto null(aucun avertissement), car chaque chemin de code attribue une valeur à name- pas besoin de s'y initialiser du tout
Code Jockey
8

Pour la plupart des logiciels qui ne sont pas réellement des logiciels de traitement de chaînes, la logique du programme ne doit pas dépendre du contenu des variables de chaîne. Chaque fois que je vois quelque chose comme ça dans un programme:

if (s == "value")

J'ai un mauvais pressentiment. Pourquoi y a-t-il une chaîne littérale dans cette méthode? Quel est le réglage s? Sait-il que la logique dépend de la valeur de la chaîne? Sait-il qu'il doit être en minuscules pour fonctionner? Dois-je résoudre ce problème en le modifiant pour l'utiliser String.Compare? Dois-je créer un Enumet l'analyser?

De ce point de vue, on arrive à une philosophie du code assez simple: on évite dans la mesure du possible d'examiner le contenu d'une chaîne. Comparer une chaîne à String.Emptyn'est en réalité qu'un cas particulier de comparaison avec un littéral: c'est quelque chose à éviter à moins que vous ne deviez vraiment le faire.

Sachant cela, je ne cligne pas des yeux quand je vois quelque chose comme ça dans notre base de code:

string msg = Validate(item);
if (msg != null)
{
   DisplayErrorMessage(msg);
   return;
}

Je sais que Validatecela ne reviendrait jamais String.Empty, car nous écrivons un meilleur code que cela.

Bien sûr, le reste du monde ne fonctionne pas comme ça. Lorsque votre programme traite des entrées utilisateur, des bases de données, des fichiers, etc., vous devez tenir compte d'autres philosophies. Là, c'est le travail de votre code d'imposer de l'ordre au chaos. Une partie de cet ordre consiste à savoir quand une chaîne vide devrait signifier String.Emptyet quand cela devrait signifier null.

(Juste pour m'assurer que je ne parlais pas de mon cul, j'ai juste cherché dans notre base de code `String.IsNullOrEmpty '. Les 54 occurrences de celui-ci sont dans des méthodes qui traitent les entrées de l'utilisateur, retournent des valeurs à partir de scripts Python, examinent les valeurs récupérées à partir de API externes, etc.)

Robert Rossney
la source
6

C'est en fait un trou béant dans le langage C #. Il n'existe aucun moyen de définir une chaîne qui ne peut pas être nulle. Cela pose des problèmes aussi simples que celui que vous décrivez, ce qui oblige les programmeurs à prendre une décision qu'ils ne devraient pas avoir à prendre, car dans de nombreux cas, NULL et String.Empty signifient la même chose. Cela, à son tour, peut plus tard forcer d'autres programmeurs à gérer à la fois NULL et String.Empty, ce qui est ennuyeux.

Un problème plus important est que les bases de données vous permettent de définir des champs qui correspondent à une chaîne C #, mais les champs de base de données peuvent être définis comme NOT NULL. Par conséquent, il n'existe aucun moyen de représenter avec précision, par exemple, un champ varchar (100) NOT NULL dans SQL Server à l'aide d'un type C #.

D'autres langues, telles que Spec #, permettent cela.

À mon avis, l'incapacité de C # à définir une chaîne qui n'autorise pas null est tout aussi mauvaise que son incapacité précédente à définir un int qui autorise null.

Pour répondre complètement à votre question: j'utilise toujours une chaîne vide pour l'initialisation par défaut, car elle ressemble plus au fonctionnement des types de données de base de données. (Edit: Cette déclaration n'était pas très claire. Elle devrait lire "J'utilise une chaîne vide pour l'initialisation par défaut lorsque NULL est un état superflu, de la même manière que j'ai configuré une colonne de base de données comme NOT NULL si NULL serait un état superflu. De même , beaucoup de mes colonnes DB sont configurées comme NOT NULL, donc quand je les amène dans une chaîne C #, la chaîne sera vide ou aura une valeur, mais ne sera jamais NULL. En d'autres termes, je n'initialise qu'une chaîne à NULL si null a une signification qui est distincte de la signification de String.Empty, et je trouve que ce cas est moins que courant (mais les gens ici ont donné des exemples légitimes de ce cas). ")

Greg Smalter
la source
L'utilisation de String.Empty n'est similaire qu'à l' une des façons dont une chaîne de base de données est définie. L'utilisation de null pour ne représenter aucune valeur est beaucoup plus congruente avec un nvarchar nul. Je pense que n'importe quel DBA digne de ce nom vous giflerait de neuf façons d'être idiot si vous utilisiez `` pour ne représenter aucune valeur.
vfilpar
En fait, Greg, vous vous trompez. Ce sont les types de valeur non Nullable qui "comment fonctionnent les types de base de données", car ils ne peuvent jamais contenir une valeur Null, et ne peuvent donc jamais mapper à une colonne Nullable. Dans le contrat, n'importe quelle chaîne peut être mappée à n'importe quelle colonne varchar.
Tor Haugen
Vous avez raison, ma dernière affirmation n'était pas assez claire. La plupart du temps, les colonnes de ma base de données ne sont PAS NULL (car il n'y aurait aucune différence entre la signification de la chaîne vide et NULL), donc j'essaye de garder mes chaînes similaires en ne stockant jamais nul dans elles, et c'est ce que je voulais dire.
Greg Smalter
5

Ça dépend.

Avez-vous besoin de pouvoir dire si la valeur est manquante (est-il possible qu'elle ne soit pas définie)?

La chaîne vide est-elle une valeur valide pour l'utilisation de cette chaîne?

Si vous avez répondu «oui» aux deux, vous voudrez utiliser null. Sinon, vous ne pouvez pas faire la différence entre "aucune valeur" et "chaîne vide".

Si vous n'avez pas besoin de savoir s'il n'y a pas de valeur, la chaîne vide est probablement plus sûre, car elle vous permet d'ignorer les vérifications nulles partout où vous l'utilisez.

Herms
la source
3

Je le mets à "" ou à null - je vérifie toujours en utilisant String.IsNullOrEmpty, donc c'est bien.

Mais le geek intérieur en moi dit que je devrais le mettre à null avant d'avoir une valeur appropriée pour cela ...

Codeur chirurgical
la source
3

Je déclare toujours string avec string.empty;

Ervin Ter
la source
2

Est-il possible qu'il s'agisse d'une technique d'évitement des erreurs (conseillée ou non ..)? Puisque "" est toujours une chaîne, vous seriez en mesure d'y appeler des fonctions de chaîne qui entraîneraient une exception si elle était NULL?

Dana le Sane
la source
1
C'est l'excuse que j'entends normalement, ça sonne juste comme de la paresse. «Je ne veux pas prendre la peine de vérifier cette valeur donc je vais prendre un raccourci», voilà ce qu'il me semble.
vfilpar
Ouais, je ne suis pas en désaccord. Il peut y avoir des situations où la réduction de la quantité de code de vérification des erreurs est bien, mais les appels de fonction qui n'ont aucun effet ne sont pas non plus les meilleurs.
Dana the Sane
2

Je les initialise toujours comme NULL.

Je toujours utiliser string.IsNullOrEmpty(someString)pour vérifier la valeur de ce.

Facile.

Pure.Krome
la source
1

Ça dépend de la situation. Dans la plupart des cas, j'utilise String.Empty parce que je ne veux pas faire de vérifications nulles à chaque fois que j'essaye d'utiliser une chaîne. Cela rend le code beaucoup plus simple et vous êtes moins susceptible d'introduire des plantages NullReferenceException indésirables.

Je ne mets la chaîne à null que lorsque j'ai besoin de savoir si elle a été définie ou non et où une chaîne vide est quelque chose de valide pour la définir. En pratique, je trouve ces situations rares.

Rob Prouse
la source
1

Une chaîne vide est une valeur (un morceau de texte qui, par ailleurs, ne contient aucune lettre). Null signifie aucune valeur.

J'initialise les variables à null lorsque je souhaite indiquer qu'elles ne pointent pas ou ne contiennent pas de valeurs réelles - lorsque l'intention est pour aucune valeur.

Yfeldblum
la source
1

En réitérant la réponse de Tomalak, gardez à l'esprit que lorsque vous assignez une variable chaîne à une valeur initiale de null, votre variable n'est plus un objet chaîne; même chose avec n'importe quel objet en C #. Donc, si vous essayez d'accéder à des méthodes ou propriétés pour votre variable et que vous supposez qu'il s'agit d'un objet chaîne, vous obtiendrez l'exception NullReferenceException.

Michael Ritchson
la source
1

Null ne doit être utilisé que dans les cas où une valeur est facultative. Si la valeur n'est pas facultative (comme «Nom» ou «Adresse»), la valeur ne doit jamais être nulle. Cela s'applique aux bases de données ainsi qu'aux POCO et à l'interface utilisateur. Null signifie "cette valeur est facultative et est actuellement absente".

Si votre champ n'est pas facultatif, vous devez l'initialiser en tant que chaîne vide. L'initialiser comme null placerait votre objet dans un état invalide (invalide par votre propre modèle de données).

Personnellement, je préférerais que les chaînes ne soient pas Nullable par défaut, mais uniquement Nullable si nous déclarons une "chaîne?". Bien que ce ne soit peut-être pas faisable ou logique à un niveau plus profond; pas certain.

Dave Cousineau
la source
0

Les chaînes ne sont pas des types de valeur et ne le seront jamais ;-)

Tor Haugen
la source
0

Je pense qu'il n'y a aucune raison de ne pas utiliser null pour une valeur non attribuée (ou à cet endroit dans un flux de programme qui ne se produit pas). Si vous voulez distinguer, il y a == null. Si vous voulez juste vérifier une certaine valeur et ne vous souciez pas de savoir si elle est nulle ou quelque chose de différent, String.Equals ("XXX", MyStringVar) fait très bien.

Volker
la source