web-dev-qa-db-fra.com

Quelle est la différence entre IEquatable et la simple substitution de Object.Equals ()?

Je veux que ma classe Food puisse tester chaque fois qu'elle est égale à une autre instance de Food. Je l'utiliserai plus tard contre une liste, et je veux utiliser sa méthode List.Contains(). Devrais-je implémenter IEquatable<Food> Ou juste écraser Object.Equals()? De MSDN:

Cette méthode détermine l'égalité à l'aide du comparateur d'égalité par défaut, défini par l'implémentation de l'objet de la méthode IEquatable.Equals pour T (type de valeurs de la liste).

Ma question suivante est donc la suivante: quelles fonctions/classes du framework .NET utilisent Object.Equals()? Devrais-je l'utiliser en premier lieu?

163
devoured elysium

La raison principale est la performance. Lorsque les génériques ont été introduits dans .NET 2.0, ils ont été en mesure d’ajouter de nombreuses classes intéressantes telles que List<T>, Dictionary<K,V>, HashSet<T>, etc. Ces structures utilisent beaucoup GetHashCode et Equals. Mais pour les types de valeur, cela nécessite une boxe. IEquatable<T> permet à une structure d'implémenter une méthode _ fortement typée Equals afin qu'aucune boxe ne soit requise. Donne donc de bien meilleures performances lors de l’utilisation de types de valeur avec des collections génériques.

Les types de référence ne sont pas aussi bénéfiques que le IEquatable<T> La mise en œuvre vous permet d'éviter un casting de System.Object qui peut faire la différence si on l’appelle fréquemment.

Comme indiqué sur le blog de Jared Parson , vous devez néanmoins implémenter les substitutions d'objet.

189
Josh

Selon le MSDN :

Si vous implémentez IEquatable<T>, Vous devez également redéfinir les implémentations de classe de base de Object.Equals(Object) et GetHashCode de sorte que leur comportement soit cohérent avec celui de la méthode IEquatable<T>.Equals. . Si vous substituez Object.Equals(Object), votre implémentation substituée est également appelée dans les appels à la méthode statique Equals(System.Object, System.Object) de votre classe. Cela garantit que tous les invocations de la méthode Equals renvoient des résultats cohérents.

Il semble donc qu'il n'y ait pas de réelle différence fonctionnelle entre les deux, si ce n'est que l'un ou l'autre pourrait être appelé en fonction de l'utilisation de la classe. Du point de vue des performances, il est préférable d’utiliser la version générique car aucune pénalité de boxing/unboxing n’y est associée.

D'un point de vue logique, il est également préférable de mettre en œuvre l'interface. Redéfinir l'objet ne dit à personne que votre classe est réellement équitable. La substitution peut simplement être une classe ne rien faire ou une implémentation superficielle. Utiliser l'interface dit explicitement: "Hé, cette chose est valable pour la vérification de l'égalité!" C'est juste un meilleur design.

45
CodexArcanum

Étendre ce que Josh a dit avec un exemple pratique. +1 à Josh - J'étais sur le point d'écrire la même chose dans ma réponse.

public abstract class EntityBase : IEquatable<EntityBase>
{
    public EntityBase() { }

    #region IEquatable<EntityBase> Members

    public bool Equals(EntityBase other)
    {
        //Generic implementation of equality using reflection on derived class instance.
        return true;
    }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as EntityBase);
    }

    #endregion
}

public class Author : EntityBase
{
    public Author() { }
}

public class Book : EntityBase
{
    public Book() { }
}

De cette façon, j'ai la méthode réutilisable Equals () qui fonctionne sans problème pour toutes mes classes dérivées.

26