L'exercice de code illustre un certain nombre de propriétés de l'égalité en C# :
Object.Equals()== et !=. C'est considéré comme plus idiomatique que d'utiliser la méthode Equals(), qui est elle aussi disponible pour ces types. Les développeurs Java doivent être attentifs, lorsqu'ils manipulent des strings, au fait que == compare par valeur en C# mais par référence en Java, quand ils reviennent à leur ancien langage.Equals() héritée de object. Si ton objectif, avec le test d'égalité, est de t'assurer que deux objets sont exactement la même instance, alors s'appuyer sur l'implémentation de object suffit. Sinon, tu dois redéfinir object.Equals().Equals() doit être redéfinie.Equals() redéfinie contiendra des tests d'égalité sur les membres de types simples à l'aide de ==, et sur les types référence avec des appels récursifs à Equals().class StatusBar
{
private readonly int width = 200, height = 20;
public override bool Equals(object other)
{
// ... null and type checks and performance optimisations
return width == (other as StatusBar).width && height == (other as StatusBar).height;
}
}
class Window
{
private readonly string title = "Main";
private readonly StatusBar statusBar = new StatusBar();
public override bool Equals(object other)
{
// ... null and type checks and performance optimisations
return title == (other as Window).title && statusBar.Equals((other as Window).statusBar);
}
}
object.ReferenceEquals() sert à comparer deux objets pour détecter s'il s'agit d'une seule et même instance. Cela apporte de la clarté et devient une nécessité lorsque Equals() et == ont été redéfinies ou surchargées.var winA = new Window(); // above code shows that all windows are equal
var winB = new Window();
ReferenceEquals(winA, winB);
// => false
var winC = winA;
ReferenceEquals(winA, winC);
// => true
public override bool Equals(object obj), les IDE génèrent généralement la surcharge protected bool Equals(FacialFeatures other) à utiliser lorsque l'héritage entre en jeu. Une classe dérivée peut appeler la méthode Equals() de la classe de base, puis ajouter son propre test.== à moins d'avoir surchargé l'opérateur == ainsi que la méthode Equals() de ta classe (voir l'exercice operator-overloading), ou à moins que seule l'égalité des références t'importe.structs sont traités dans l'exercice structs.tuples est traitée dans l'exercice tuples.protected bool Equals(T other)
{
return field1 == other.field1 && field2.Equals(other.field2);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((T) obj);
}
SequenceEquals(), mais en l'absence de LINQ, il faut parcourir les deux collections et comparer les éléments un par un.== et != avec tes propres classes, voir l'exercice operator-overloading.Object.GetHashCode()object.GetHashCode() renvoie un code de hachage sous la forme d'un entier de 32 bits. Le code de hachage est utilisé par les classes dictionnaire et ensemble telles que Dictionary<T> et HashSet<T> pour stocker et récupérer des objets de manière performante. Dans le cas des dictionnaires, le hachage concerne les clés.Equals(), tu redéfinisses aussi GetHashCode(). Il existe une relation entre Equals() et GetHashCode() qui doit être respectée pour que les classes dictionnaire et ensemble de hachage, ainsi que toutes celles qui utilisent un code de hachage, se comportent correctement. Tu es censé implémenter la méthode de telle sorte à ne pas tendre de pièges aux mainteneurs qui pourraient ajouter plus tard une collection basée sur un code de hachage.Equal() renvoie true), alors GetHashCode() doit renvoyer la même valeur pour ces deux objets. Cela ne s'applique pas dans le sens inverse. La relation n'est pas symétrique. Imagine une fonction de recherche qui se rend d'abord dans un « compartiment » en fonction du code de hachage, puis sélectionne l'élément particulier à l'aide du test d'égalité.HashCode.Combine() en lui passant les valeurs utilisées dans le test d'égalité (ou un sous-ensemble). Garde à l'esprit que plus tu fournis d'informations à Combine(), plus l'implémentation du hachage sera performante.public class Assessment
{
private int rating;
private Person boss;
public override int GetHashCode()
{
return HashCode.Combine(rating, boss);
}
}
Pour améliorer légèrement les performances, en particulier lorsque les objets appartiennent à des collections, tu peux ajouter un membre surchargé public bool Equals(T other).
Cela économisera un certain nombre de vérifications de type pour les types référence et économisera une étape de boxing pour les types valeur, car ils n'auront pas besoin d'être convertis en objet (boxed) comme argument de public override bool Equals(object other).
Si tu ajoutes l'interface IEquatable<T> à ta classe, cela t'obligera à implémenter la surcharge. À moins que ton code ne contienne des routines qui prennent des objets de type IEquatable<T> (et qui font sans doute quelque chose d'intéressant en rapport avec l'égalité, indépendamment de la classe qui l'implémente), il n'y a vraiment aucune autre raison impérieuse d'inclure cette interface.
IEqualityComparer<T>Si tu as une classe qui peut être identifiée de manière unique de deux façons différentes, par exemple une classe Person qui possède un SSID et une adresse e-mail unique, alors .NET fournit un moyen de permettre à deux collections différentes d'utiliser des tests de code de hachage et d'égalité différents. Chacune peut avoir une implémentation différente de IEqualityComparer<T> avec sa propre méthode Equals() et sa propre méthode GetHashCode(). Tu peux avoir un dictionnaire indexé par SSID et un autre indexé par adresse e-mail.
Lorsque IEqualityComparer<T> entre en jeu, tu redéfinis généralement quand même Equals() et GetHashCode() sur ta classe d'élément pour éviter des problèmes en dehors des classes de collection.
Une considération, lorsque tu utilises IEqualityComparer<T>, est que les méthodes privées, etc., ne seront pas disponibles pour le test d'égalité.
Si une seule collection hachée est en jeu, il peut être préférable d'éviter IEqualityComparer<T> et d'encapsuler l'égalité et le code de hachage dans l'objet lui-même. Il n'est déjà pas idéal qu'une dépendance essentielle comme celle entre un objet et une collection hachée ne puisse pas être imposée par le compilateur, mais si la logique de hachage et de comparaison se trouve ailleurs, il serait encore plus facile pour un mainteneur de modifier les membres d'une classe sans se soucier des conséquences pour la collection.
Une primitive qui peut déstabiliser le développeur imprudent est le test de l'égalité des valeurs à virgule flottante. Ce sujet est abordé dans le document about.md du concept floating-point-numbers.
Cet article présente quelques-unes des décisions à prendre en matière d'égalité et d'héritage. Elles ne te concerneront que si tu manipules des instances d'une classe et d'une classe dérivée et que tu dois tester l'égalité entre les deux.