Je pense que la conception de .NET rend un exercice aussi simple que la vérification de l'égalité des objets un peu difficile.
Pour Struct
1) Mise en œuvre IEquatable<T>
. Il améliore sensiblement les performances.
2) Puisque vous avez votre propre Equals
maintenant, passer outre GetHashCode
et pour être cohérent avec les différents contrôles de l'égalité, il convient d'ignorer les règles de l'Union européenne. object.Equals
également.
3) Surcharge ==
y !=
n'ont pas besoin d'être religieusement utilisés puisque le compilateur vous avertira si vous assimilez involontairement une structure à une autre avec un opérateur ==
o !=
mais il est bon de le faire pour être cohérent avec les règles de l'Union européenne. Equals
des méthodes.
public struct Entity : IEquatable<Entity>
{
public bool Equals(Entity other)
{
throw new NotImplementedException("Your equality check here...");
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is Entity))
return false;
return Equals((Entity)obj);
}
public static bool operator ==(Entity e1, Entity e2)
{
return e1.Equals(e2);
}
public static bool operator !=(Entity e1, Entity e2)
{
return !(e1 == e2);
}
public override int GetHashCode()
{
throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
}
}
Pour la classe
De MS :
La plupart des types de référence ne doivent pas surcharger l'opérateur d'égalité, même s'ils surchargent Equals.
Pour moi ==
ressemble à une égalité de valeur, plus qu'à un sucre syntaxique pour les Equals
méthode. L'écriture a == b
est beaucoup plus intuitif que d'écrire a.Equals(b)
. Il est rare que nous devions vérifier l'égalité des références. Dans les niveaux abstraits traitant des représentations logiques d'objets physiques, ce n'est pas quelque chose que nous devrions vérifier. Je pense que le fait d'avoir une sémantique différente pour ==
y Equals
peut en fait être source de confusion. Je pense qu'il aurait fallu ==
pour l'égalité des valeurs et Equals
pour référence (ou un meilleur nom comme IsSameAs
) en premier lieu. J'aimerais ne pas prendre au sérieux la ligne directrice sur les EM, non seulement parce qu'elle n'est pas naturelle pour moi, mais aussi parce qu'elle est surchargée ==
n'a pas d'effet néfaste majeur. C'est la différence avec le fait de ne pas passer par-dessus des Equals
o GetHashCode
qui peut mordre, parce que le cadre n'utilise pas de ==
n'importe où, mais seulement si nous l'utilisons nous-mêmes. Le seul véritable avantage que je retire de ne pas surcharger ==
y !=
sera la cohérence avec la conception de l'ensemble du cadre, sur laquelle je n'ai aucun contrôle. Et c'est effectivement une chose importante, Je m'en tiendrai donc malheureusement à cela .
Avec une sémantique de référence (objets mutables)
1) Annulation Equals
y GetHashCode
.
2) Mise en œuvre IEquatable<T>
n'est pas indispensable, mais sera utile si vous en avez un.
public class Entity : IEquatable<Entity>
{
public bool Equals(Entity other)
{
if (ReferenceEquals(this, other))
return true;
if (ReferenceEquals(null, other))
return false;
//if your below implementation will involve objects of derived classes, then do a
//GetType == other.GetType comparison
throw new NotImplementedException("Your equality check here...");
}
public override bool Equals(object obj)
{
return Equals(obj as Entity);
}
public override int GetHashCode()
{
throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
}
}
Avec une sémantique de valeur (objets immuables)
C'est la partie la plus délicate. Elle peut être facilement perturbée si l'on n'y prend pas garde
1) Annulation Equals
y GetHashCode
.
2) Surcharge ==
y !=
pour correspondre Equals
. S'assurer qu'il fonctionne pour les nullités .
2) Mise en œuvre IEquatable<T>
n'est pas indispensable, mais sera utile si vous en avez un.
public class Entity : IEquatable<Entity>
{
public bool Equals(Entity other)
{
if (ReferenceEquals(this, other))
return true;
if (ReferenceEquals(null, other))
return false;
//if your below implementation will involve objects of derived classes, then do a
//GetType == other.GetType comparison
throw new NotImplementedException("Your equality check here...");
}
public override bool Equals(object obj)
{
return Equals(obj as Entity);
}
public static bool operator ==(Entity e1, Entity e2)
{
if (ReferenceEquals(e1, null))
return ReferenceEquals(e2, null);
return e1.Equals(e2);
}
public static bool operator !=(Entity e1, Entity e2)
{
return !(e1 == e2);
}
public override int GetHashCode()
{
throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
}
}
Faites particulièrement attention à ce qu'il se passe si votre classe peut être héritée, dans ce cas vous devrez déterminer si un objet de la classe de base peut être égal à un objet de la classe dérivée. Idéalement, si aucun objet de la classe dérivée n'est utilisé pour vérifier l'égalité, alors une instance de la classe de base peut être égale à une instance de la classe dérivée et, dans ce cas, il n'est pas nécessaire de vérifier la conformité des objets de la classe dérivée. Type
l'égalité dans les produits génériques Equals
de la classe de base.
En général, il faut veiller à ne pas dupliquer le code. J'aurais pu créer une classe de base abstraite générique ( IEqualizable<T>
) comme modèle pour faciliter la réutilisation, mais malheureusement, en C#, cela m'empêche de dériver à partir de classes supplémentaires.