Je trouve étrange qu'on vous null.ToString()donne ce nom wtf. Pourquoi cela vous surprend-il? Vous ne pouvez pas appeler une méthode d'instance lorsque vous n'avez rien à partir duquel l'appeler en premier lieu.
BoltClock
11
@BoltClock: Bien sûr, il est possible d'appeler une méthode d'instance sur une instance nulle. Juste pas possible en C #, mais très valable sur le CLR :)
leppie
1
Les réponses concernant String.Concat sont presque correctes. En fait, l'exemple spécifique de la question est celui d' un repliement constant , et les valeurs nulles de la première ligne sont éliminées par le compilateur - c'est-à-dire qu'elles ne sont jamais évaluées à l'exécution car elles n'existent plus - le compilateur les a effacées. J'ai écrit un petit monologue sur toutes les règles de concaténation et de pliage constant des chaînes ici pour plus d'informations: stackoverflow.com/questions/9132338/… .
Chris Shain
77
vous ne pouvez rien ajouter à une chaîne, mais vous ne pouvez pas créer une chaîne à partir de rien.
RVB
La deuxième déclaration n'est-elle pas valide? class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
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.
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 remplacée. Sinon, tout argument non-chaîne est converti en sa représentation sous forme de chaîne en appelant la ToStringméthode virtuelle héritée de type object.
Si ToStringretourne 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, une référence qui ne fait référence à aucun objet. null est la valeur par défaut des variables de type référence.
Cela fonctionnerait-il alors? var wtf = ((String)null).ToString();Je travaille récemment en Java où le cast de null est possible, cela fait un moment que j'ai travaillé avec C #.
Jochem
14
@Jochem: Vous essayez toujours d'appeler une méthode sur un objet nul, donc je suppose que non. Pensez-y comme null.ToString()vs ToString(null).
Svish
@Svish oui, maintenant j'y repense, c'est un objet nul, donc tu as raison, ça ne marchera pas. Ce ne serait pas non plus en Java: exception de pointeur nul. Ça ne fait rien. Tnx pour votre réponse! [modifier: testé en Java: NullPointerException. Avec la différence qu'avec le cast, il compile, sans le cast, il ne le fait pas].
Jochem
il n'y a généralement aucune raison de concaténer ou de ToString intentionnellement le mot clé null. Si vous avez besoin d'une chaîne vide, utilisez string.Empty. si vous avez besoin de vérifier si une variable chaîne est nulle, vous pouvez utiliser (myString == null) ou string.IsNullOrEmpty (myString). Vous pouvez également transformer une variable de chaîne nulle en chaîne.Empty utiliser myNewString = (myString == null ?? string.Empty)
csauve
@Jochem le castant le fera compiler mais il lancera effectivement une NullReferenceException au moment de l'exécution
jeroenh
108
Parce que l' +opérateur en C # se traduit en interne par String.Concat, qui est une méthode statique. Et cette méthode se traite nullcomme une chaîne vide. Si vous regardez la source de String.ConcatReflector, vous la verrez:
// while looping through the parameters
strArray[i]=(str ==null)?Empty: str;// then concatenate that string array
Il n'y a cependant pas d'opérateur + dans la classe String. Alors, est-ce le compilateur qui traduit en String.Concat?
superlogical
@superlogical Oui, c'est ce que fait le compilateur. Donc en fait, l' +opérateur sur les chaînes en C # n'est que du sucre syntaxique pour String.Concat.
Botz3000
Ajout à cela: le compilateur sélectionne automatiquement la surcharge de Concat qui a le plus de sens. Les surcharges disponibles sont 1, 2 ou 3 paramètres d'objet, 4 paramètres d'objet + __arglistet une paramsversion de tableau d'objets.
Wormbo
Quel tableau de chaînes y est modifié? Crée-t-il Concattoujours un nouveau tableau de chaînes non nulles même lorsqu'on lui donne un tableau de chaînes non nulles, ou est-ce qu'il se passe autre chose?
supercat
@supercat Le tableau modifié est un nouveau tableau, qui est ensuite passé à une méthode d'assistance privée. Vous pouvez consulter le code vous-même à l'aide du réflecteur.
Botz3000
29
Le premier échantillon sera traduit en:
var bob =String.Concat("abc123",null,null,null,"abs123");
La Concatméthode 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 nullexception de référence sera donc générée ici
Je viens de le faire :) ((object)null).ToString()=> AccessViolation((object)1 as string).ToString()=>NullReference
leppie
1
J'ai NullReferenceException. DN 4.0
Viacheslav Smityukh
Intéressant. Quand je mets à l' ((object)null).ToString()intérieur, try/catchje reçois NullReferenceExceptionaussi.
leppie
3
@Ieppie sauf que cela ne lance pas non plus AccessViolation (pourquoi le ferait-il?) - NullReferenceException ici.
jeroenh
11
La première partie de votre code est simplement traitée comme ça dans String.Concat,
qui est ce que le compilateur C # appelle lorsque vous ajoutez des chaînes. " abc" + nullest traduit en String.Concat("abc", null),
et en interne, cette méthode remplace nullpar String.Empty. C'est pourquoi votre première partie de code ne lève aucune exception. c'est juste 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 nulle , 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.
String.Emptyn'est pas égal à null. C'est juste traité de la même manière dans certaines méthodes comme String.Concat. Par exemple, si vous avez une variable de chaîne définie sur null, C # ne la remplacera pas par String.Emptysi vous essayez d'appeler une méthode dessus.
Botz3000
3
Presque. nulln'est pas traité comme String.Emptypar C #, il est simplement traité comme ça dans String.Concat, ce que le compilateur C # appelle lorsque vous ajoutez des chaînes. "abc" + nullest traduit en String.Concat("abc", null), et en interne, cette méthode remplace nullpar String.Empty. La deuxième partie est tout à fait correcte.
Botz3000
9
Dans le framework COM qui a précédé .net, il était nécessaire que toute routine recevant une chaîne la libère lorsqu'elle en avait fini avec elle. Étant donné qu'il était très courant que des chaînes vides soient passées dans et hors des routines et que la tentative de «libération» d'un pointeur nul était définie comme une opération légitime de ne rien faire, Microsoft a décidé de faire en sorte qu'un pointeur de chaîne nulle représente une chaîne vide.
Pour permettre une certaine compatibilité avec COM, de nombreuses routines dans .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 nullobjets du 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>fonctionner un peu différemment (afin de permettre - Nullable<String>quelque chose qu'ils auraient dû faire de toute façon à mon humble avis) et / ou définir un NullableStringtype qui serait principalement interchangeable avec String, mais qui ne considérerait pas un nullcomme une chaîne vide valide.
En l'état, il existe certains contextes dans lesquels a nullsera considéré comme une chaîne vide légitime et d'autres dans lesquels il ne le sera pas. Ce n'est pas une situation très utile, mais une situation dont les programmeurs devraient être conscients. En général, les expressions du formulaire stringValue.someMemberéchoueront si stringValuec'est le cas null, mais la plupart des méthodes et opérateurs du framework qui acceptent des chaînes comme paramètres seront considérés nullcomme une chaîne vide.
'+'est un opérateur d'infixe. Comme tout opérateur, il appelle vraiment une méthode. Vous pouvez imaginer une version non infixée"wow".Plus(null) == "wow"
Le réalisateur a décidé de quelque chose comme ça ...
Vraiment, c'est plutôt var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");. Les surcharges d'opérateurs sont des méthodes statiques au cœur: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Si elles ne l'étaient pas, var bob = null + "abc";ou surtout string bob = null + null;ne seraient pas valides.
Ben Mosher
Vous avez raison, je pensais juste que je serais trop déroutant si je l'expliquais de cette façon.
Nigel Thorne
3
Je suppose que c'est un littéral qui ne fait référence à aucun objet. ToString()a besoin d'un object.
Quelqu'un a dit dans ce fil de discussion que vous ne pouvez pas créer de chaîne avec rien.
(qui est une belle phrase comme je pense). 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 d'exception. La seule différence est que vous devez convertir l'une des valeurs nulles en une chaîne - si vous supprimez la conversion (chaîne) , l'exemple se compile toujours, mais lève une exception d'exécution: "L'opérateur '+' est ambigu sur les opérandes de tapez '<null>' et '<null>' ".
NB Dans l'exemple de code ci-dessus, la valeur de x n'est pas nulle comme on pourrait s'y attendre, c'est en fait une chaîne vide après avoir transtypé l'un des opérandes en une chaîne.
Un autre fait intéressant est qu'en C # / .NET, la manière dont nullest 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());
Regardez la 1ère ligne de l'extrait de code: si xest une variable entière Nullable (c'est-à-dire int?) contenant une valeur 1, alors vous récupérez le résultat <null>. S'il s'agit d'une chaîne (comme indiqué dans le commentaire) avec une valeur "1", vous récupérez "1"plutôt que <null>.
NB Aussi 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 xen type de données int, qui n'est pas nullable. Le compilateur ne suppose pas int?ici, et échoue donc dans la 2ème ligne où nullest ajouté.
L'ajout nullà une chaîne est simplement ignoré. null(dans votre deuxième exemple) n'est une instance d'aucun objet, donc il n'a même pas de ToString()méthode. C'est juste un littéral.
Parce qu'il n'y a aucune différence entre string.Emptyet nullquand vous concattez des chaînes. Vous pouvez également transmettre null string.Format. Mais vous essayez d'appeler une méthode on null, ce qui entraînerait toujours un NullReferenceExceptionet donc générerait 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 nullet retourne string.Empty. Mais une extension comme celle-ci ne devrait être utilisée que lorsqu'elle est absolument nécessaire (à mon avis).
En général: il peut ou non valider l'acceptation de null comme paramètre en fonction de la spécification, mais il est toujours invalide d'appeler une méthode sur null.
C'est et un autre sujet pourquoi les opérandes de l'opérateur + peuvent être nuls dans le cas de chaînes. C'est un peu quelque chose de VB (désolé les gars) pour faciliter la vie des programmeurs, 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' + 'n'importe quoi' doit être toujours 'inconnu' ...
null.ToString()
donne ce nomwtf
. Pourquoi cela vous surprend-il? Vous ne pouvez pas appeler une méthode d'instance lorsque vous n'avez rien à partir duquel l'appeler en premier lieu.class null_extension { String ToString( Object this arg ) { return ToString(arg); } }
Réponses:
La raison pour laquelle le premier fonctionne:
Depuis MSDN :
Plus d'informations sur l' opérateur binaire + :
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, une référence qui ne fait référence à aucun objet. null est la valeur par défaut des variables de type référence.
la source
wtf = ((String)null).ToString();
Je travaille récemment en Java où le cast de null est possible, cela fait un moment que j'ai travaillé avec C #.null.ToString()
vsToString(null)
.Parce que l'
+
opérateur en C # se traduit en interne parString.Concat
, qui est une méthode statique. Et cette méthode se traitenull
comme une chaîne vide. Si vous regardez la source deString.Concat
Reflector, vous la verrez:(MSDN le mentionne également: http://msdn.microsoft.com/en-us/library/k9c94ey1.aspx )
D'autre part,
ToString()
est une méthode d'instance, que vous ne pouvez pas appelernull
(pour quel type utilisernull
?).la source
+
opérateur sur les chaînes en C # n'est que du sucre syntaxique pourString.Concat
.__arglist
et uneparams
version de tableau d'objets.Concat
toujours un nouveau tableau de chaînes non nulles même lorsqu'on lui donne un tableau de chaînes non nulles, ou est-ce qu'il se passe autre chose?Le premier échantillon sera traduit en:
La
Concat
méthode vérifie l'entrée et traduit null comme une chaîne videLe deuxième échantillon sera traduit en:
Une
null
exception de référence sera donc générée icila source
AccessViolationException
sera jeté :)((object)null).ToString()
=>AccessViolation
((object)1 as string).ToString()
=>NullReference
((object)null).ToString()
intérieur,try/catch
je reçoisNullReferenceException
aussi.La première partie de votre code est simplement 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 enString.Concat("abc", null)
,et en interne, cette méthode remplace
null
parString.Empty
. C'est pourquoi votre première partie de code ne lève aucune exception. c'est juste commeEt 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 nulle , 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.la source
String.Empty
n'est pas égal ànull
. C'est juste traité de la même manière dans certaines méthodes commeString.Concat
. Par exemple, si vous avez une variable de chaîne définie surnull
, C # ne la remplacera pas parString.Empty
si vous essayez d'appeler une méthode dessus.null
n'est pas traité commeString.Empty
par C #, il est simplement traité comme ça dansString.Concat
, ce que le compilateur C # appelle lorsque vous ajoutez des chaînes."abc" + null
est traduit enString.Concat("abc", null)
, et en interne, cette méthode remplacenull
parString.Empty
. La deuxième partie est tout à fait correcte.Dans le framework COM qui a précédé .net, il était nécessaire que toute routine recevant une chaîne la libère lorsqu'elle en avait fini avec elle. Étant donné qu'il était très courant que des chaînes vides soient passées dans et hors des routines et que la tentative de «libération» d'un pointeur nul était définie comme une opération légitime de ne rien faire, Microsoft a décidé de faire en sorte qu'un pointeur de chaîne nulle représente une chaîne vide.
Pour permettre une certaine compatibilité avec COM, de nombreuses routines dans .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
null
objets du type déclaré String se comportent encore plus comme des chaînes vides. Si Microsoft avait fait cela, il aurait également dû faireNullable<T>
fonctionner un peu différemment (afin de permettre -Nullable<String>
quelque chose qu'ils auraient dû faire de toute façon à mon humble avis) et / ou définir unNullableString
type qui serait principalement interchangeable avecString
, mais qui ne considérerait pas unnull
comme une chaîne vide valide.En l'état, il existe certains contextes dans lesquels a
null
sera considéré comme une chaîne vide légitime et d'autres dans lesquels il ne le sera pas. Ce n'est pas une situation très utile, mais une situation dont les programmeurs devraient être conscients. En général, les expressions du formulairestringValue.someMember
échoueront sistringValue
c'est le casnull
, mais la plupart des méthodes et opérateurs du framework qui acceptent des chaînes comme paramètres seront considérésnull
comme une chaîne vide.la source
'+'
est un opérateur d'infixe. Comme tout opérateur, il appelle vraiment une méthode. Vous pouvez imaginer une version non infixée"wow".Plus(null) == "wow"
Le réalisateur a décidé de quelque chose comme ça ...
Alors ... votre exemple devient
qui est le même que
À aucun moment, null ne devient une chaîne. Ce
null.ToString()
n'est donc pas différent de celanull.VoteMyAnswer()
. ;)la source
var bob = Plus(Plus(Plus(Plus("abc",null),null),null),"123");
. Les surcharges d'opérateurs sont des méthodes statiques au cœur: msdn.microsoft.com/en-us/library/s53ehcz3(v=VS.71).aspx Si elles ne l'étaient pas,var bob = null + "abc";
ou surtoutstring bob = null + null;
ne seraient pas valides.Je suppose que c'est un littéral qui ne fait référence à aucun objet.
ToString()
a besoin d'unobject
.la source
Quelqu'un a dit dans ce fil de discussion que vous ne pouvez pas créer de chaîne avec rien. (qui est une belle phrase comme je pense). Mais oui - vous pouvez :-), comme le montre l'exemple suivant:
fonctionne bien et ne lève pas du tout d'exception. La seule différence est que vous devez convertir l'une des valeurs nulles en une chaîne - si vous supprimez la conversion (chaîne) , l'exemple se compile toujours, mais lève une exception d'exécution: "L'opérateur '+' est ambigu sur les opérandes de tapez '<null>' et '<null>' ".
NB Dans l'exemple de code ci-dessus, la valeur de x n'est pas nulle comme on pourrait s'y attendre, c'est en fait une chaîne vide après avoir transtypé l'un des opérandes en une chaîne.
Un autre fait intéressant est qu'en C # / .NET, la manière dont
null
est traitée n'est pas toujours la même si vous considérez différents types de données. Par exemple:Regardez la 1ère ligne de l'extrait de code: si
x
est une variable entière Nullable (c'est-à-direint?
) contenant une valeur1
, alors vous récupérez le résultat<null>
. S'il s'agit d'une chaîne (comme indiqué dans le commentaire) avec une valeur"1"
, vous récupérez"1"
plutôt que<null>
.NB Aussi 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 variablex
en type de donnéesint
, qui n'est pas nullable. Le compilateur ne suppose pasint?
ici, et échoue donc dans la 2ème ligne oùnull
est ajouté.la source
L'ajout
null
à une chaîne est simplement ignoré.null
(dans votre deuxième exemple) n'est une instance d'aucun objet, donc il n'a même pas deToString()
méthode. C'est juste un littéral.la source
Parce qu'il n'y a aucune différence entre
string.Empty
etnull
quand vous concattez des chaînes. Vous pouvez également transmettre nullstring.Format
. Mais vous essayez d'appeler une méthode onnull
, ce qui entraînerait toujours unNullReferenceException
et donc générerait 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
et retournestring.Empty
. Mais une extension comme celle-ci ne devrait être utilisée que lorsqu'elle est absolument nécessaire (à mon avis).la source
En général: il peut ou non valider l'acceptation de null comme paramètre en fonction de la spécification, mais il est toujours invalide d'appeler une méthode sur null.
C'est et un autre sujet pourquoi les opérandes de l'opérateur + peuvent être nuls dans le cas de chaînes. C'est un peu quelque chose de VB (désolé les gars) pour faciliter la vie des programmeurs, 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' + 'n'importe quoi' doit être toujours 'inconnu' ...
la source