Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Conseil / Astuce
Cet article fait partie de la section Notions de base pour les développeurs qui connaissent déjà au moins un langage de programmation et apprennent C#. Si vous débutez avec la programmation, commencez par commencer par les didacticiels De prise en main .
Venant d’une autre langue ? Dans Java, == appliqué aux objets, et en JavaScript, === appliqué aux objets, testent l’identité, et non le contenu. Les classes C# fonctionnent de la même façon par défaut. En Python, == appelle __eq__ et compare le contenu par défaut, à l’instar des records en C#. Les structs C# comparent également par valeur lorsque vous appelez Equals.
C# distingue deux types d’égalité. L’égalité des valeurs signifie que deux instances sont égales lorsque leurs données correspondent. L’égalité de référence signifie que deux variables sont égales uniquement lorsqu’elles pointent vers le même objet en mémoire. Cette condition est également appelée identité. Les types valeur comparent généralement les données et les types de référence comparent généralement l’identité. Les auteurs de types peuvent modifier ces valeurs par défaut, mais ce modèle mental empêche les bogues subtils où deux objets qui semblent identiques ne sont pas considérés comme égaux, ou où une mutation par le biais d’une variable change silencieusement ce qu’une autre variable voit.
Types de valeur, types de référence et comportements d’égalité par défaut
Chaque type en C# est soit un type valeur , soit un type référence. Un type valeur contient ses données directement dans la variable. Un type référence contient une référence à un objet. Lorsque vous affectez une variable de type référence à une autre variable, les deux variables font référence au même objet. Pour plus d’informations sur les types de valeur et les types de référence, consultez Vue d’ensemble du système de types.
Le comportement d’égalité par défaut dépend généralement de la nature du type :
-
Les types numériques intégrés et les énumérations sont des types valeur. Deux
intvariables sont égales lorsque leurs valeurs numériques correspondent. - Les Structs sont des types de valeur. Une simple
structutilise l’égalité des valeurs lorsque vous appelez Equals. - Tuples sont des types de valeur. Deux tuples sont égaux lorsque toutes leurs valeurs d’élément correspondent.
-
Les classes sont des types de référence. Une classe simple repose sur l’égalité de référence ; ainsi,
==et Equals permettent de vérifier si deux variables pointent vers le même objet.
Une classe utilise l’égalité de référence. Deux objets distincts avec les mêmes données ne sont pas égaux, mais deux variables qui font référence au même objet sont égales :
var order1 = new Order(42, "Shoes");
var order2 = new Order(42, "Shoes");
Console.WriteLine(order1 == order2); // => False
Console.WriteLine(order1.Equals(order2)); // => False
Console.WriteLine(ReferenceEquals(order1, order2)); // => False
Order order3 = order1;
Console.WriteLine(order1 == order3); // => True
Un struct indique l’égalité de valeur via Equals. Deux instances de struct sont égales lorsque leurs champs correspondent :
var pt1 = new Point(3, 4);
var pt2 = new Point(3, 4);
Console.WriteLine(pt1.Equals(pt2)); // => True
Les structs bruts n’obtiennent pas d’opérateur prédéfini == . L’écriture p1 == p2 sur un struct brut compile uniquement si le struct déclare son propre operator ==. Si vous avez besoin de comparaisons d’opérateurs pour un struct, définissez == et != en tant que paire et conservez-les cohérentes avec Equals et GetHashCode.
Les tuples sont également des types de valeur. Deux tuples sont égaux lorsque la valeur de chaque élément est identique. Les noms d’éléments dans un tuple nommé sont pratiques au moment de la compilation et ne sont pas pris en compte lors de la comparaison. Seules les positions et valeurs sont importantes :
var t1 = (Name: "Grace", Role: "Engineer");
var t2 = (Name: "Grace", Role: "Engineer");
Console.WriteLine(t1 == t2); // => True
Pour plus d’informations sur la syntaxe des tuples et la déconstruction, consultez Tuples et déconstruction.
Utiliser Object.ReferenceEquals pour tester directement l’identité
ReferenceEquals teste toujours l’identité, quelle que soit la manière dont un type redéfinit Equals ou surcharge ==. Utilisez-le comme diagnostic d’identité lorsque vous devez confirmer si deux variables pointent vers le même objet exactement :
var doc1 = new Document("Report");
var doc2 = new Document("Report");
var doc3 = doc1;
Console.WriteLine(ReferenceEquals(doc1, doc2)); // => False
Console.WriteLine(ReferenceEquals(doc1, doc3)); // => True
Une utilisation courante consiste à utiliser une surcharge de Equals afin d’éviter une comparaison complète : lorsque les deux arguments font référence au même objet, ils sont toujours égaux sans vérifier chaque champ individuellement.
Note
Lorsque les variables sont typées en tant qu’interface, == vérifie si les variables d’interface font référence au même objet. Un appel à Equals exécute toujours l’implémentation de l’objet sous-jacent.
Note
ReferenceEquals retourne false toujours lors de la comparaison des types valeur, même si les deux arguments contiennent les mêmes valeurs. Ce comportement se produit parce que chaque argument de type valeur est boxé indépendamment dans un objet tas distinct lorsqu’il est passé à ReferenceEquals.
Les types peuvent définir une sémantique d’égalité différente
Les types peuvent définir la sémantique d’égalité qui diffère du comportement par défaut. La raison la plus courante est d’implémenter l’égalité des valeurs. Si vous créez un type qui représente des données, telles qu’un compte bancaire, un produit en inventaire ou un utilisateur dans un système, envisagez des instances avec les mêmes valeurs que celles égales. Choisissez les types d’enregistrements pour implémenter l’égalité des valeurs, et le compilateur génère tous les membres d’égalité nécessaires pour vous.
Note
Les chaînes sont des classes, mais == et Equals comparent le contenu de chaîne, et non l’identité.
-
==: opérateur d’égalité. La plupart des types utilisent cet opérateur comme contrôle d’égalité principal. Son comportement dépend du fait que le type possède un opérateur==intégré ou défini par l’utilisateur. -
!=: opérateur d’inégalité. Lorsqu’un type définit un opérateur==défini par l’utilisateur, il doit également définir!=. - Equals: méthode virtuelle héritée par chaque type. Vous pouvez le remplacer pour modifier la sémantique d’égalité d’un type.
- GetHashCode: méthode virtuelle utilisée par les collections basées sur le hachage. Lorsque deux valeurs sont égales, leurs codes de hachage doivent également être égaux.
- ReferenceEquals: méthode statique qui teste toujours l’identité.
Utiliser des enregistrements pour l’égalité des valeurs
Utilisez le record modificateur pour donner une égalité de valeur de type axé sur les données lorsque le type peut être un enregistrement. Le compilateur génère Equals, GetHashCodeet ==/!= les membres qui comparent chaque valeur de propriété déclarée.
Un record class reste un type de référence, mais il compare les valeurs plutôt que l’identité :
var person1 = new Person("Ada", "Lovelace");
var person2 = new Person("Ada", "Lovelace");
Console.WriteLine(person1 == person2); // => True
Console.WriteLine(person1.Equals(person2)); // => True
Console.WriteLine(ReferenceEquals(person1, person2)); // => False
ReferenceEquals confirme que person1 et person2 sont des objets différents en mémoire, tandis que == et Equals renvoient True, car l’égalité générée par le compilateur compare la valeur des propriétés.
La même génération de compilateur s’applique aux record struct types :
var dim1 = new Dimension(1920, 1080);
var dim2 = new Dimension(1920, 1080);
Console.WriteLine(dim1 == dim2); // => True
Console.WriteLine(dim1.Equals(dim2)); // => True
Les types d’enregistrements génèrent l’ensemble de l’égalité définie pour leur propre type. Les deux record class types record struct remplacent Equals et GetHashCode. Ils génèrent également les opérateurs == et !=, ainsi qu’une méthode typée Equals pour le type record. Contrairement à une simple struct, une record struct prend donc en charge == et != automatiquement. Pour plus d’informations sur les types d’enregistrements et leur sémantique d’égalité, consultez Enregistrements.
Records avec des membres de type référence
L’égalité des enregistrements utilise la sémantique d’égalité des membres. Chaque propriété ou champ est comparé à l’aide de sa propre Equals méthode. Pour la plupart des valeurs scalaires, telles que int, stringou DateTime, cette approche compare les valeurs des membres d’enregistrement. La subtilité se produit avec des collections mutables courantes telles que List<T> ou T[]: ces types comparent par référence, donc deux instances d’enregistrement qui contiennent différents objets de liste avec le même contenune sont pas considérées comme égales par l’égalité des enregistrements synthétisées.
var playlist1 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
var playlist2 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
Console.WriteLine(playlist1.Equals(playlist2)); // => False (different List instances)
Console.WriteLine(playlist1.Tracks.SequenceEqual(playlist2.Tracks)); // => True
playlist1 et playlist2 sont des instances distinctes List<string> . Même si leur contenu correspond, Equals retourne false.
Lorsque vous avez besoin d’une égalité d’enregistrement pour refléter le contenu de la collection, vous avez quelques options :
-
Implémentez
IEquatable<T>dans l’enregistrement et redéfinissezEqualspour utiliser Enumerable.SequenceEqual pour les éléments de la collection. -
Utilisez un type de collection avec égalité par valeur — par exemple, un
IEqualityComparer<T>personnalisé ou un type dont leEqualscompare ses éléments. - Concevoir autour de l’identité : si l’enregistrement représente une entité plutôt qu’une valeur pure, l’égalité de référence pour ses membres de collection peut être intentionnelle.
Important
L’implémentation manuelle de l’égalité est rare aujourd’hui en C#. Les enregistrements gèrent automatiquement le scénario courant de l’égalité des valeurs. Si vous devez implémenter l’égalité manuellement, par exemple parce que votre type doit dériver d’une classe de base qui n’est pas un enregistrement, consultez Implémenter l’égalité vous-même lorsqu’un type ne peut pas être un enregistrement dans la référence du langage.
Voir aussi
- Vue d’ensemble du système de type
- Classes
- Structures
- Enregistrements
- Tuples et déconstruction.
- Opérateurs d’égalité (référence de langue).
- Égalité dans les hiérarchies de classes : conseils avancés sur l’égalité polymorphe.
- Opérateurs arithmétiques, de comparaison, logiques et d’affectation : l’enquête des opérateurs d’égalité avec les opérateurs arithmétiques, logiques et d’affectation.