web-dev-qa-db-fra.com

Pourquoi est-il valide de concaténer des chaînes nulles mais pas d'appeler "null.ToString ()"?

Ceci est un code C # valide

var bob = "abc" + null + null + null + "123";  // abc123

Ce n'est pas un code C # valide

var wtf = null.ToString(); // compiler error

Pourquoi la première déclaration est-elle valide?

121
superlogical

La raison du premier travail:

De MSDN :

Dans les opérations de concaténation de chaînes, le compilateur C # traite une chaîne nulle de la même manière qu'une chaîne vide, mais il ne convertit pas la valeur de la chaîne nulle d'origine.

Plus d'informations sur + opérateur binaire :

L'opérateur binaire + effectue la concaténation de chaînes lorsqu'un ou les deux opérandes sont de type chaîne.

Si un opérande de concaténation de chaînes est nul, une chaîne vide est substituée. Sinon, tout argument non-chaîne est converti en sa représentation sous forme de chaîne en appelant la méthode virtuelle ToString héritée de l'objet type.

Si ToString renvoie null, une chaîne vide est remplacée.

La raison de l'erreur en seconde est:

null (référence C #) - Le mot clé null est un littéral qui représente une référence null, qui ne fait référence à aucun objet. null est la valeur par défaut des variables de type référence.

159
Pranay Rana

Parce que l'opérateur + En C # se traduit en interne par String.Concat, Qui est une méthode statique. Et cette méthode arrive à traiter null comme une chaîne vide. Si vous regardez la source de String.Concat Dans Reflector, vous le verrez:

// while looping through the parameters
strArray[i] = (str == null) ? Empty : str;
// then concatenate that string array

(MSDN le mentionne également: http://msdn.Microsoft.com/en-us/library/k9c94ey1.aspx )

D'un autre côté, ToString() est une méthode d'instance, que vous ne pouvez pas appeler sur null (quel type doit être utilisé pour null?).

107
Botz3000

premier échantillon sera traduit en:

var bob = String.Concat("abc123", null, null, null, "abs123");

La méthode Concat vérifie l'entrée et traduit null comme une chaîne vide

Le deuxième échantillon sera traduit en:

var wtf = ((object)null).ToString();

Une exception de référence null sera donc générée ici

29

La première partie de votre code est traitée comme ça dans String.Concat,

qui est ce que le compilateur C # appelle lorsque vous ajoutez des chaînes. "abc" + null Est traduit en String.Concat("abc", null),

et en interne, cette méthode remplace null par String.Empty. C'est pourquoi votre première partie de code ne lève aucune exception. c'est comme

var bob = "abc" + string.Empty + string.Empty + string.Empty + "123";  //abc123

Et dans la 2ème partie de votre code lève une exception car 'null' n'est pas un objet, le mot clé null est un littéral qui représente une référence null, celui qui ne fait référence à aucun objet. null est la valeur par défaut des variables de type référence.

Et 'ToString()' est une méthode qui peut être appelée par une instance d'un objet mais pas par n'importe quel littéral.

11
Talha

Dans le cadre COM qui précédait .net, il était nécessaire que toute routine qui recevait une chaîne la libère lorsqu'elle en avait fini avec elle. Parce qu'il était très courant que des chaînes vides soient passées dans et hors des routines, et parce que la tentative de "libérer" un pointeur nul était définie comme une opération légitime de ne rien faire, Microsoft a décidé qu'un pointeur de chaîne nul représente une chaîne vide.

Pour permettre une certaine compatibilité avec COM, de nombreuses routines en .net interpréteront un objet nul comme une représentation légale comme une chaîne vide. Avec quelques légères modifications .net et ses langages (permettant notamment aux membres d'instance d'indiquer "ne pas invoquer comme virtuel"), Microsoft aurait pu faire en sorte que les objets null de type déclaré String se comportent encore plus comme des chaînes vides. Si Microsoft avait fait cela, il aurait également dû faire Nullable<T> fonctionne quelque peu différemment (afin de permettre à Nullable<String>-- quelque chose qu'ils devraient avoir fait à mon humble avis de toute façon) et/ou définir un type NullableString qui serait principalement interchangeable avec String, mais qui ne considérerait pas un null comme une chaîne vide valide.

En l'état, il existe certains contextes dans lesquels un null sera considéré comme une chaîne vide légitime et d'autres dans lesquels il ne le sera pas. Pas une situation extrêmement utile, mais une situation dont les programmeurs devraient être conscients. En général, les expressions de la forme stringValue.someMember échouera si stringValue est null, mais la plupart des méthodes de framework et des opérateurs qui acceptent des chaînes comme paramètres considéreront null comme une chaîne vide.

9
supercat

'+' Est un opérateur d'infixe. Comme tout opérateur, il appelle vraiment une méthode. Vous pourriez imaginer une version non infixe "wow".Plus(null) == "wow"

Le réalisateur a décidé quelque chose comme ça ...

class String
{
  ...
  String Plus(ending)
  {
     if(ending == null) return this;
     ...
  }
} 

Alors .. votre exemple devient

var bob = "abc".Plus(null).Plus(null).Plus(null).Plus("123");  // abc123

ce qui est le même que

var bob = "abc".Plus("123");  // abc123

A aucun moment, null ne devient une chaîne. Donc null.ToString() n'est pas différent de null.VoteMyAnswer(). ;)

5
Nigel Thorne

Quelqu'un a dit dans ce fil de discussion que vous ne pouvez pas faire une chaîne à partir de rien. (ce qui est une belle phrase à mon avis). Mais oui - vous pouvez :-), comme le montre l'exemple suivant:

var x = null + (string)null;     
var wtf = x.ToString();

fonctionne bien et ne lève pas du tout une exception. La seule différence est que vous devez transtyper l'une des valeurs nulles dans une chaîne - si vous supprimez la conversion (chaîne), alors l'exemple compile toujours, mais lève une exception au moment de l'exécution: "Opérateur" + 'est ambigu sur les opérandes de type' <null> 'et' <null> '".

N.B. Dans l'exemple de code ci-dessus, la valeur de x n'est pas nulle comme vous pouvez vous y attendre, il s'agit en fait d'une chaîne vide après avoir casté l'un des opérandes dans une chaîne.


Un autre fait intéressant est qu'en C #/.NET la façon dont null est traitée n'est pas toujours la même si vous considérez différents types de données. Par exemple:

int? x = 1;  //  string x = "1";
x = x + null + null;
Console.WriteLine((x==null) ? "<null>" : x.ToString());

En ce qui concerne 1ère ligne de l'extrait de code: si x est une variable entière nullable (c'est-à-dire int?) contenant la valeur 1, vous obtenez le résultat <null> retour. S'il s'agit d'une chaîne (comme indiqué dans le commentaire) avec la valeur "1", alors vous obtenez "1" retour plutôt que <null>.

N.B. Également intéressant: si vous utilisez var x = 1; pour la première ligne, vous obtenez une erreur d'exécution. Pourquoi? Parce que l'affectation transformera la variable x en type de données int, qui n'est pas nullable. Le compilateur ne suppose pas int? ici, et donc échoue dans la 2ème ligne où null est ajouté.

3
Matt

Je suppose que c'est un littéral qui ne fait référence à aucun objet. ToString() a besoin d'un object.

3
Saeed Neamati

L'ajout de null à une chaîne est simplement ignoré. null (dans votre deuxième exemple) n'est une instance d'aucun objet, il n'a donc même pas de méthode ToString(). C'est juste un littéral.

2
Thorsten Dittmar

Parce qu'il n'y a pas de différence entre string.Empty et null lorsque vous concattez des chaînes. Vous pouvez passer null dans string.Format ainsi que. Mais vous essayez d'appeler une méthode sur null, ce qui entraînerait toujours un NullReferenceException et générerait donc une erreur de compilation.
Si pour une raison quelconque vous voulez vraiment le faire, vous pouvez écrire une méthode d'extension, qui vérifie null puis retourne string.Empty. Mais une extension comme celle-ci ne devrait être utilisée qu'en cas de nécessité absolue (à mon avis).

1
Franky

En général: il peut ou non valider l'acceptation de null comme paramètre selon la spécification, mais il n'est pas toujours valide d'appeler une méthode sur null.


C'est et d'autres sujets pourquoi les opérandes de l'opérateur + peuvent être nuls en cas de chaînes. C'est un peu VB chose (désolé les gars) pour rendre la vie des programmeurs plus facile, ou en supposant que le programmeur ne peut pas gérer les valeurs nulles. Je suis complètement en désaccord avec cette spécification. 'Inconnu' + ​​'tout' devrait être toujours 'inconnue'...

0
g.pickardou