Le premier cas compare 2 références au même objet (String.Empty
). L'appel de operator==
pour 2 variables object
provoque leur comparaison par référence et donne true
.
Le deuxième cas produit 2 instances différentes de la classe de chaîne de caractères. Leur comparaison de référence donne false
Si vous donnez le type string
à x
et y
dans le deuxième cas, l'override de string.operator==
sera appelé et la comparaison donnera true
Notez que nous ne traitons pas directement l'internage des chaînes de caractères dans les deux cas. Les objets de chaîne que nous comparons sont créés en utilisant le constructeur string(char[])
. Apparemment, ce constructeur est conçu pour renvoyer la valeur du champ string.Empty
lorsqu'il est appelé avec un tableau vide comme argument.
La réponse publiée par MarcinJuraszek renvoie au blog de Lippert qui traite de l'internage des chaînes de caractères. Ce billet de blog discute d'un autre cas particulier de l'utilisation de la classe de chaîne de caractères. Considérez cet exemple du blog de Lippert mentionné ci-dessus :
object obj = "";
string str1 = "";
string str2 = String.Empty;
Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true
Console.WriteLine(obj == str2); // parfois vrai, parfois faux ?!
Ce que nous voyons ici, c'est que l'assignation du littéral de chaîne vide (""
) n'est pas garantie de produire la référence au champ statique en lecture seule System.String.Empty
.
Regardons le langage intermédiaire (IL) pour l'expression object x = new string("".ToArray());
:
IL_0001: ldstr ""
IL_0006: call !!0[] [System.Core]System.Linq.Enumerable::ToArray(class [mscorlib]System.Collections.Generic.IEnumerable`1)
IL_000b: newobj instance void [mscorlib]System.String::.ctor(char[])
IL_0010: stloc.0
L'internage peut (ou non) se produire à la ligne IL_0001. Que le littéral soit interné ou non, la méthode ToArray()
produit un nouveau tableau vide et le String::.ctor(char[])
nous donne String.Empty
.
Ce que nous voyons ici n'est pas le cas spécial de string.Empty
mais plutôt l'un des effets secondaires du fait que la classe de string
soit à la fois un type de référence et immuable. Il existe d'autres types immuables du framework qui ont des valeurs prédéfinies avec des sémantiques similaires (comme DateTime.MinValue
). Mais autant que je sache, ces types du framework sont définis comme des struct
contrairement au string
qui est un type de référence. Les types de valeur sont une toute autre histoire... Il n'a pas de sens de retourner une instance de type prédéfinie fixe à partir d'un constructeur de classe mutable (le code appelant sera en mesure de changer cette instance et de provoquer un comportement imprévisible du type). Ainsi, les types de référence dont les constructeurs ne renvoient pas toujours de nouvelles instances peuvent exister à condition que ces types soient immuables. Je ne connais cependant pas d'autres types de ce genre dans le framework, sauf le string
.
0 votes
Quelle version de .NET utilisez-vous qui vous permet de convertir un élément de chaîne unique en un tableau ? Ou peut-être devrais-je demander quels éléments vous utilisez ?
0 votes
@AdamZuckerman chaîne est un Ienumerable de caractères....
0 votes
Alors vous avez inclus LINQ aussi?
0 votes
@AdamZuckerman cela n'a pas d'importance. Si vous le souhaitez, vous pouvez utiliser
String.ToCharArray
c'est la même chose1 votes
Si vous comparez comme ceci
x.Equals(y)
, alors cela renverra true0 votes
intern
n'est pas nécessaire car les littéraux sont internés par défaut. Pouvez-vous également vérifier si la machine dispose uniquement de .net3.5 ou .Net4.0 ? car le comportement de String.Empty a changé à partir de .Net 4.5 Peut-être que c'est la raison!0 votes
@dholakiyaankit mais c'est une comparaison de valeurs mec, nous parlons de l'égalité des références ici
0 votes
Si vous modifiez le premier exemple pour utiliser
object x = new String("k".ToArray());
, la comparaison échoue également.0 votes
Ok je ne sais pas pourquoi cela se produit?
0 votes
C'est vraiment une bonne question
0 votes
@dholakiyaankit car les chaînes sont comparées par valeur au lieu de référence voir : msdn.microsoft.com/en-us/library/362314fe.aspx
0 votes
Merci beaucoup @Selman22
2 votes
Alors le texte "k" ne devrait-il pas être égal à l'autre texte "k" s'ils sont comparés par valeur ?
0 votes
Aussi, en utilisant
object c = new String(String.Empty.ToArray());
se compare à True.0 votes
@AdamZuckerman mais ils sont définis comme objet donc comparés par référence. Si vous les définissez comme une chaîne de caractères, alors cela renverra vrai.
0 votes
@RoyiNamir Comme je l'ai dit plus tôt, quelqu'un doit tester cela avec une machine qui n'a même pas .Net 4.5 installé. Vous avez .Net 4.5 installé, n'est-ce pas ? Donc cela ne servira à rien car de nouveaux binaires de .Net 4.5 seront utilisés même si vous ciblez .net 2.0.
0 votes
@SriramSakthivel 4.5 étend/remplace fw 4. pas 2. si vous avez installé 2, il l'utilisera. (imho). (et je l'ai installé)
0 votes
@RoyiNamir Oui, peut-être que j'ai tort à ce sujet
0 votes
En utilisant la nouvelle Source de Référence, nous pouvons facilement voir que dans le code source : string.cs, ligne 1687, et ligne 1722. Bien sûr, ce n'est qu'une implémentation, vous devriez vous en remettre à la spécification, pas au code source.
0 votes
@Kobi s'il te plaît convertis ton commentaire en réponse..
0 votes
@Royi - J'ai cherché après l'avoir lu la réponse principale, donc elle est déjà là: "Certaines versions du runtime .NET internent automatiquement la chaîne vide pendant l'exécution, d'autres non!". Mais merci!
0 votes
@Kobi J'ai un problème pour le sélectionner car 98% de la réponse concerne des choses que je connais déjà et que j'ai mentionnées. (comme je l'ai dit: ça ne m'aide pas). Seule sa dernière ligne répond vraiment à la question. Mais la vôtre fournit également le code source.
0 votes
Quelqu'un peut-il ajouter un lien vers le quiz s'il vous plaît?
1 votes
Je ne suis pas sûr pourquoi vous avez accepté la réponse ci-dessous, elle n'a même pas abordé le contenu de la question. Dans votre premier exemple, vous avez utilisé des constructeurs de string pour instancier les chaînes vides. Cela aurait dû donner des références complètement nouvelles et non les mêmes.
0 votes
@JeffMercado vous n'avez pas lu les réponses. Une chaîne vide à l'exécution est également interprétée
1 votes
J'ai fait, mais le
""
littéral etString.Empty
sont des bêtes différentes quenew String(new char[0])
. Autant que je sache, aucune des réponses n'aborde vraiment cela. Et la citation du blog d'Eric Lippert a été sortie de son contexte. Cela parlait de littéraux de chaîne vides et deString.Empty
. Le cas de deux chaînes nouvellement créées indépendamment, qui se trouvent être vides, reste flou. Toutes les réponses ont simplement dansé autour de cette explication de manière pratique.0 votes
@jeff Certaines versions de l'exécution .NET internent automatiquement la chaîne vide à l'exécution, d'autres ne le font pas. Ainsi, la valeur de la nouvelle chaîne ("".toarray()) sera également internée car il s'agit d'une chaîne vide en résultat
1 votes
Ouais, je me concentre probablement trop sur ce morceau. En lisant cela dans le contexte du blog, cela me semble différent pour une raison quelconque. L'idée de
new T() != new T()
pour tous lesT
n'est pas toujours vraie, cela me bluffe en ce moment.