Domanda

Come funziona l'operatore == in C #? Se viene utilizzato per confrontare oggetti della classe A , proverà ad abbinare tutte le proprietà di A o cercherà i puntatori nella stessa posizione di memoria (o forse qualcos'altro)?

Creiamo un esempio ipotetico. Sto scrivendo un'applicazione che utilizza l'API di Twitter e ha una classe Tweet , che ha tutte le proprietà di un singolo tweet: testo, mittente, data e ora, sorgente, ecc. Se voglio confrontare oggetti della classe Tweet per equivalenza, posso semplicemente usare:

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

Questo verificherà l'equivalenza di tutte le proprietà della classe Tweet tra a e b ?

In caso contrario, l'approccio corretto sarebbe quello di sovraccaricare l'operatore == per verificare esplicitamente l'equivalenza di tutti i campi?

AGGIORNAMENTO: Dalle prime due risposte, ho ragione nel dare per scontato:

  • Se l'operatore == o il metodo Equals non è sovraccaricato per una classe, l'operatore == per l'oggetto viene utilizzata la classe.
  • L'operatore == per la classe oggetto verifica l'uguaglianza nella posizione della memoria.
  • Devo sovraccaricare l'operatore == o il metodo Equals per eseguire questo compito.
  • Nel sovraccarico, devo verificare manualmente l'equivalenza nelle proprietà, quindi non c'è modo di farlo in modo semi-automatico, diciamo, in un ciclo , giusto?

AGGIORNAMENTO # 2: Yuriy ha commentato che è possibile verificare l'equivalenza delle proprietà nell'operatore == con riflesso . Come si può fare? Potresti darmi qualche codice di esempio? Grazie!

È stato utile?

Soluzione

MSDN ha un buon esempio di come farlo:

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

Quindi sovraccarichi == e! =:

// 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;
   }

E non dimenticare di sovraccaricare il metodo GetHash.

Modifica:

Ho scritto il seguente esempio rapido per usare la riflessione in un confronto. Questo dovrebbe essere molto più completo, potrei provare a fare un blog su di esso se la gente lo vuole:

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;
    }
}

Altri suggerimenti

Per i tipi di riferimento, le implementazioni predefinite sia dell'operatore == che del metodo Equals () controlleranno semplicemente che entrambi gli oggetti abbiano lo stesso riferimento e sono quindi la stessa istanza.

Se vuoi controllare che il contenuto di due diversi oggetti sia uguale, devi scrivere il codice per farlo da solo, in un modo o nell'altro. Sarebbe possibile avere a che fare con la riflessione (il MbUnit fa qualcosa di simile) ma con un pesante penalità prestazionali e una buona probabilità che non farebbe comunque quello che ti aspettavi, e dovresti implementare == o Equals e GetHashCode di mano.

L'approccio corretto è il sovraccarico del metodo uguale alla classe Tweet oltre all'operatore ==, come descritto qui .

  

Verificherà l'equivalenza di tutte le proprietà della classe Tweet tra aeb?

No

  

In caso contrario, l'approccio corretto sarebbe sovraccaricare l'operatore == per verificare esplicitamente l'equivalenza di tutti i campi?

Puoi sovraccaricare l'operatore == o sovraccaricare la funzione Uguali .

Modifica

@Yuriy ha dato un buon esempio per confrontare tutte le variabili non pubbliche. Dato che ho anche scritto un esempio, eccolo qui (il mio confronta le proprietà)

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;
    }
}

Puoi confrontare le proprietà usando reflection:

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;
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top