44 votes

Opérateur de surcharge C # == versus Equals ()

Je suis en train de travailler sur un projet C# pour qui, jusqu'à présent, j'ai utilisé des objets immuables et les usines afin de s'assurer que les objets de type Foo peut toujours être comparé pour l'égalité avec l' ==. Foo objets ne peut pas être changé une fois créé, et l'usine renvoie toujours le même objet pour un ensemble donné d'arguments. Cela fonctionne très bien, et tout au long de la base de code, nous supposons que == travaille toujours pour la vérification de l'égalité.

Maintenant, j'ai besoin d'ajouter quelques fonctionnalités qui présente un cas limite pour lequel cela ne fonctionne pas toujours. La meilleure chose à faire est de surcharger operator == pour ce type, de sorte qu'aucun autre code dans le projet qui doit changer. Mais ce qui me frappe comme une odeur de code: surcharge operator == et pas Equals semble juste bizarre, et je suis habitué à la convention qu' == des contrôles de référence de l'égalité, et Equals vérifie objet d'égalité (ou peu importe le terme).

Est-ce une préoccupation légitime, ou devrais-je simplement aller de l'avant et de surcharge operator ==?

89voto

Samuel Neff Points 35554

Il y a une grande différence entre la surcharge == et impérieuse d' égal à Égal.

Lorsque vous avez l'expression

if (x == y) {

La méthode qui sera utilisée pour comparer les variables x et y est décidé lors de la compilation du temps. C'est la surcharge d'opérateur. Le type utilisé lors de la déclaration de x et y est utilisé pour définir la méthode utilisée pour comparer. Le type réel à l'intérieur de x et y (c'est à dire, une sous-classe ou de l'interface de mise en œuvre) n'est pas pertinente. Considérons l'exemple suivant.

object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference

if (x == y) { // evaluates to FALSE

et la suite

string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference

if (x == y) { // evaluates to TRUE

Cela démontre que le type utilisé pour déclarer les variables x et y est utilisé pour déterminer la méthode utilisée pour évaluer ==.

Par comparaison, est Égal à est déterminé au moment de l'exécution, sur la base du type de la variable x. Égale est une méthode virtuelle sur l'Objet que d'autres types peuvent remplacer. Par conséquent, les deux exemples suivants évalués à la valeur true.

object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference

if (x.Equals(y)) { // evaluates to TRUE

et la suite

string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference

if (x.Equals(y)) { // also evaluates to TRUE

28voto

McKay Points 7281

Je crois que la norme est que pour la plupart des types, .Equals vérifie la similitude des objets et l'opérateur == vérifie l'égalité de référence.

Je crois que la meilleure pratique est que pour les types immuables, l'opérateur == devrait vérifier la similitude, ainsi que .Equals . Et si vous voulez savoir s'il s'agit vraiment du même objet, utilisez .ReferenceEquals . Voir la classe C # String pour un exemple de cela.

7voto

Mike Sackton Points 236

Pour immuable types je ne pense pas qu'il n'y a rien de mal à avoir == surchargé à l'appui de la valeur de l'égalité. Je ne pense pas que je voudrais remplacer == sans écraser Equals à avoir la même sémantique cependant. Si vous ne remplacent == et besoin de vérifier la référence de l'égalité, pour une raison quelconque, vous pouvez utiliser Object.ReferenceEquals(a,b).

Voir cet article de Microsoft pour certaines lignes directrices utiles

7voto

Henk Holterman Points 153608

Ça sent vraiment. Lors de la surcharge de == vous devez vous assurer que Equals() et GetHashCode() sont également cohérents. Voir les directives MSDN .

Et la seule raison pour laquelle cela semble OK, c'est que vous décrivez votre type comme immuable.

7voto

John Points 344

Exemple montrant comment implémenter cela selon les directives MSFT (ci-dessous). Notez que lorsque vous remplacez Equals, vous devez également remplacer GetHashCode (). J'espère que cela aide les gens.

 public class Person
{
    public Guid Id { get; private set; }

    public Person(Guid id)
    {
        Id = id;
    }

    public Person()
    {
        Id = System.Guid.NewGuid();
    }

    public static bool operator ==(Person p1, Person p2)
    {
        bool rc;

        if (System.Object.ReferenceEquals(p1, p2))
        {
            rc = true;
        }
        else if (((object)p1 == null) || ((object)p1 == null))
        {
            rc = false;
        }
        else
        {
            rc = (p1.Id.CompareTo(p2.Id) == 0);
        }

        return rc;
    }

    public static bool operator !=(Person p1, Person p2)
    {
        return !(p1 == p2);
    }

    public override bool Equals(object obj)
    {
        bool rc = false;
        if (obj is Person)
        {
            Person p2 = obj as Person;
            rc = (this == p2);
        }
        return rc;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}
 

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