Question

Comment l'opérateur == fonctionne-t-il vraiment en C #? S'il comparait des objets de la classe A , tentera-t-il de faire correspondre toutes les propriétés de A ou cherchera-t-il des pointeurs sur le même emplacement mémoire (ou peut-être quelque chose d'autre)?

Créons un exemple hypothétique. J'écris une application qui utilise l'API Twitter et une classe Tweet qui possède toutes les propriétés d'un tweet unique: texte, expéditeur, date, heure, source, etc. Si je voulez comparer les objets de la classe Tweet pour l'équivalence, puis-je utiliser:

Tweet a, b;
if (a == b)
{
//do something...
}

Cela vérifiera-t-il l'équivalence de toutes les propriétés de la classe Tweet entre a et b ?

Si ce n'est pas le cas, serait la bonne approche pour surcharger l'opérateur == afin de vérifier explicitement l'équivalence de tous les champs?

UPDATE: Parmi les deux premières réponses, ai-je raison de supposer:

  • Si l'opérateur == ou la méthode Equals n'est pas surchargé pour une classe, l'opérateur == de l'objet la classe est utilisée.
  • L'opérateur == de la classe objet vérifie l'égalité dans l'emplacement mémoire.
  • Je dois surcharger l'opérateur == ou la méthode Equals pour accomplir cette tâche.
  • En cas de surcharge, je dois vérifier l'équivalence des propriétés manuellement. par conséquent, il n'est pas possible de le faire de manière semi-automatique, par exemple dans une boucle , n'est-ce pas?

MISE À JOUR N ° 2: Yuriy a déclaré qu'il était possible de vérifier l'équivalence des propriétés dans l'opérateur == avec réflexion . . Comment cela peut-il être fait? Pourriez-vous me donner un exemple de code? Merci!

Était-ce utile?

La solution

MSDN a un bon exemple sur comment le faire:

   public override bool Equals(object o) 
   {
      try 
      {
         return (bool) (this == (DBBool) o);
      }
      catch 
      {
         return false;
      }
   }

Ensuite, vous surchargez le == et! =:

// Equality operator. Returns dbNull if either operand is dbNull, 
   // otherwise returns dbTrue or dbFalse:
   public static DBBool operator ==(DBBool x, DBBool y) 
   {
      if (x.value == 0 || y.value == 0) return dbNull;
      return x.value == y.value? dbTrue: dbFalse;
   }

   // Inequality operator. Returns dbNull if either operand is
   // dbNull, otherwise returns dbTrue or dbFalse:
   public static DBBool operator !=(DBBool x, DBBool y) 
   {
      if (x.value == 0 || y.value == 0) return dbNull;
      return x.value != y.value? dbTrue: dbFalse;
   }

Et n'oubliez pas de surcharger la méthode GetHash.

Modifier:

J'ai écrit l'exemple rapide suivant pour utiliser la réflexion dans une comparaison. Cela devrait être beaucoup plus complet, je pourrais peut-être essayer de faire un blog si les gens veulent que je:

public class TestEquals
{
    private int _x;
    public TestEquals(int x)
    {
        this._x = x;
    }

    public override bool Equals(object obj)
    {
        TestEquals te = (TestEquals)obj;
        if (te == null) return false;

        foreach (var field in typeof(TestEquals)
            .GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
        {
            if (!field.GetValue(this).Equals(field.GetValue(te)))
                return false;
        }
        return true;
    }
}

Autres conseils

Pour les types de référence, les implémentations par défaut de l'opérateur == et de la méthode Equals () vont simplement vérifier que les deux objets ont la même référence et sont donc la même instance.

Si vous souhaitez vérifier que le contenu de deux objets différents est égal, vous devez écrire le code pour le faire vous-même, d'une manière ou d'une autre. Il serait possible de faire de la réflexion (le cadre de test MbUnit fait quelque chose dans ce sens) mais avec une lourde pénalité de performance et une bonne chance qu’il ne fasse pas tout à fait ce que vous espériez, et vous devez implémenter == ou est égal à et GetHashCode par main.

L’approche appropriée consiste à surcharger la méthode equals de la classe Tweet en plus de l’opérateur ==, comme indiqué ici .

  

Cela vérifiera-t-il l'équivalence de toutes les propriétés de la classe Tweet entre a et b?

Non

  

Sinon, la bonne approche consisterait-elle à surcharger l'opérateur == afin de vérifier explicitement l'équivalence de tous les champs?

Vous pouvez surcharger l'opérateur == ou la fonction Equals .

Modifier

@Yuriy a donné un bon exemple de compilation de toutes les variables non publiques. Depuis que j’ai aussi écrit un exemple, le voici (le mien compare les propriétés)

class TwitterItem
{
    private string myValue = "default value";
    public string Value1
    {
        get { return myValue; }
        set { myValue = value; }
    }
    public string Value2
    {
        get { return myValue; }
        set { myValue = value; }
    }
    public string Value3
    {
        get { return myValue; }
        set { myValue = value; }
    }

    public override bool Equals(object obj)
    {
        if (base.Equals(obj)) return true;

        Type type = typeof(TwitterItem);
        PropertyInfo[] properties = type.GetProperties();

        foreach (PropertyInfo property in properties)
        {
            if (false == property.GetValue(this, null).Equals(property.GetValue(obj, null)))
                return false;
        }

        return true;
    }
}

Vous pouvez comparer les propriétés à l'aide de la réflexion:

var a = new Entity() { Name = "test", ID = "1" };
var b = new Entity() { Name = "test", ID = "1" };
var c = new Entity() { Name = "test", ID = "2" };
System.Diagnostics.Debug.WriteLine(a.Equals(b));//Returns true
System.Diagnostics.Debug.WriteLine(a.Equals(c));//Returns false


public class Entity
{
    public string Name { get; set; }
    public string ID { get; set; }
    public override bool Equals(object obj)
    {
        var t = obj.GetType();
        foreach (var p in t.GetProperties())
        {
            if (t.GetProperty(p.Name).GetValue(obj, null) != t.GetProperty(p.Name).GetValue(this, null))
                return false;
        }
        return true;
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top