71 votes

Comparer une chaîne et un objet en C#

Voir ce code :

object x = "mehdi emrani";
string y = "mehdi emrani";
Console.WriteLine(y == x);

qui renvoie true .

Mais ce code :

object x = "mehdi emrani";
string y = "mehdi ";
y += "emrani";
Console.WriteLine(y == x);

retours false .

Ainsi, lorsque je compare String et Object dans le premier code, j'obtiens true .
Mais lorsque je les compare dans le deuxième code, j'obtiens false .

Les deux chaînes sont identiques, mais lorsque je les ajoute à la chaîne, le résultat est le suivant false ?

0 votes

Pour comparer des chaînes de caractères, vous devez toujours utiliser la fonction .Equals fonction

3 votes

@RononDex Il dit Pourquoi ?

11 votes

@RononDex : c'est vrai pour java mais pas pour C#, normalement on compare des chaînes de caractères, puis la fonction == est surchargé, ce qui présente l'avantage de pouvoir gérer les null correctement.

94voto

Jon Skeet Points 692016

Dans chaque cas, le deuxième opérande de == es x qui est du type object . Cela signifie que vous utilisez l'opérateur d'égalité de référence normal.

Dans le premier cas, vous utilisez deux chaînes de caractères constantes avec le même contenu. Le compilateur C# utilisera un seul objet pour ces deux références. Dans le second cas, x y y renvoient à des objets distincts de type chaîne de caractères ayant le même contenu. Les deux références seront différentes, donc == renverra un message faux.

Vous pouvez corriger la comparaison en procédant comme suit

  • Utilisation Equals à la place - c'est surdéterminé por string (par opposition à la == qui n'est que surchargé :

    Console.WriteLine(y.Equals(x)); // or x.Equals(y), or Equals(y, x)

    L'utilisation du système statique Equals(object, object) peut être utile si l'un des arguments peut être nul ; cela signifie que vous n'avez pas à vous soucier d'une méthode NullReferenceException .

  • Les deux variables doivent être de type string à ce moment-là, le == surcharge à l'intérieur string sera choisi à la compilation, et cette surcharge compare le contenu des chaînes, et pas seulement les références

Il convient de noter qu'il ne s'agit pas seulement d'une question de chaînes de caractères littérales remarquées par le compilateur C#, mais aussi d'expressions constantes à la compilation. Ainsi, par exemple :

object x = "mehdi emrani";
string y = "mehdi " + "emrani";
Console.WriteLine(y == x); // True

Ici y est initialisé à l'aide de deux chaînes de caractères littérales qui ne sont pas le même que celui utilisé pour initialiser x mais la concaténation de la chaîne est effectuée par le compilateur, qui se rend compte qu'il s'agit de la même chaîne que celle qu'il a déjà utilisée pour x .

0 votes

Je pense qu'il serait approprié de mentionner l'expression "string interning", qui est la raison pour laquelle le premier cas de l'OP fonctionne, même s'ils sont comparés en tant qu'objets parce qu'ils sont le même objet. J'ajoute que la première comparaison utilisant l'objet == doit être évité.

2 votes

@flindeberg : J'ai évité d'utiliser le terme interning parce qu'il est souvent considéré comme une opération au moment de l'exécution, alors qu'il s'agit ici d'une opération au moment de la compilation - le compilateur n'émettra qu'une seule chaîne de caractères, de sorte que le CLR n'aura pas besoin d'interner quoi que ce soit.

0 votes

Également Console.WriteLine( string.Intern(y) == x ) ; imprime vrai. Dans le cas où vous savez déjà que x est interné

33voto

Zaheer Ahmed Points 12945

Lorsque vous avez initialisé

object x = "mehdi emrani";  //pointer(x)

Il l'a initialisé dans la mémoire et lui a assigné une référence à x. Après cela, lorsque vous avez initialisé

string y = "mehdi emrani"; //pointer(x)

ref

le compilateur constate que cette valeur est déjà en mémoire et attribue donc la même référence à y.

Ahora == L'opérateur equal, qui compare les adresses au lieu de la valeur, trouve la même adresse pour les deux variables, ce qui donne un résultat correct :

x==y  //actually compares pointer(x)==pointer(x) which is true

Dans le second cas, lorsque vous initialisez x et y, des adresses différentes leur sont attribuées.

object x = "mehdi emrani";  //Pointer(x)
string y = "mehdi ";        //not found in memory
y += "emrani";              //Pointer(y)

Maintenant, la comparaison trouve des adresses différentes qui donnent des résultats erronés :

x == y  //is actually Pointer(x) == Pointer(y) which is false

Pour y remédier, vous devez donc utiliser la fonction Equals() qui, au lieu de la référence, compare la valeur et le type d'objet.

Console.WriteLine(y.Equals(x));   //compares "mehdi emrani" == "mehdi emrani" results true

0 votes

Êtes-vous sûr que si vous affectez une valeur littérale de chaîne à une chaîne, il vérifie s'il existe déjà une chaîne identique en mémoire et affecte ce pointeur ? Si c'est le cas, je pense que c'est une mauvaise décision. Si je devais y += " veci " ; cela changerait également x. Je pense que vous voulez dire y = x ; ce qui définirait le pointeur

0 votes

@Chad 1) toutes les constantes de chaînes égales partagent la même instance puisqu'elles sont internées. Cela inclut les constantes formées par concaténation. Mais cela n'inclut pas la concaténation qui se produit au moment de l'exécution. 2) += ne modifie pas la valeur du côté gauche. Elle crée une nouvelle instance et l'affecte à la variable. x += y est très similaire à x = x + y en C# (contrairement à C++ où il peut s'agir d'une opération de mutation distincte).

0 votes

@CodesinChaos - Avez-vous des références pour étayer ces propos et fournir des lectures complémentaires ? Si c'est vrai, je pense que c'est quelque chose d'important à comprendre pleinement.

7voto

Grzenio Points 16802

Le plus souvent, les références sont comparées (standard Equals pour l'objet). Dans le premier exemple, C# optimise les chaînes de caractères constantes, et donc y et x pointent en fait vers le même objet, et leur référence est donc égale. Dans l'autre cas, y est créé dynamiquement, et la référence est donc différente.

7voto

Dans le premier cas, .NET optimise les constantes de chaîne et n'alloue qu'une seule instance de chaîne. x et y pointent tous deux vers le même objet (les deux références sont égales).

Mais dans le second cas, x et y renvoient à des instances de chaînes différentes. L'ajout de "ermani" à y crée un troisième objet de type chaîne.

L'opérateur "==" renvoie en principe un résultat positif si les opérandes des deux côtés se réfèrent au même objet. Dans le premier cas, x et y font référence au même objet et dans le second cas, x et y font référence à des objets différents.

6voto

DaveDev Points 9630

En arrière-plan, une nouvelle chaîne est créée chaque fois que vous modifiez une chaîne existante, car les chaînes sont immuables, ce qui signifie qu'elles ne peuvent pas changer.

Voir les explications suivantes : Pourquoi les chaînes de caractères .NET sont-elles immuables ?

3 votes

À mon avis, cela n'explique pas vraiment ce qui se passe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X