Должен ли я перегружать == оператор? - PullRequest
3 голосов
/ 29 октября 2009

Как оператор == действительно работает в C #? Если он раньше сравнивал объекты класса A , попытается ли он сопоставить все свойства A или будет искать указатели на ту же ячейку памяти (или, возможно, что-то еще) )

Давайте создадим гипотетический пример. Я пишу приложение, которое использует Twitter API, и у него есть класс Tweet , который имеет все свойства одного твита: текст, отправитель, дата и время, источник и т. Д. Если я хочу сравнить объекты класса Tweet для эквивалентности, могу ли я просто использовать:

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

Будет ли проверять эквивалентность всех свойств класса Tweet между a и b ?

Если нет, будет правильным подходом перегрузить оператор == для явной проверки на эквивалентность всех полей?

ОБНОВЛЕНИЕ: Из первых двух ответов я прав, предполагая:

  • Если оператор == или метод Equals не перегружен для класса, используется оператор == для класса object .
  • Оператор == для объекта класса проверяет равенство в ячейке памяти.
  • Мне нужно перегрузить оператор == или метод Equals для выполнения этой задачи.
  • При перегрузке я должен проверять эквивалентность свойств вручную, поэтому нет способа сделать это полуавтоматически, скажем, в цикле , верно?

ОБНОВЛЕНИЕ № 2: Юрий отметил, что можно проверить эквивалентность свойств в операторе == с отражением . Как это может быть сделано? Не могли бы вы дать мне пример кода? Спасибо!

Ответы [ 5 ]

4 голосов
/ 29 октября 2009

Для ссылочных типов реализации по умолчанию как оператора ==, так и метода Equals() просто проверят, что оба объекта имеют одинаковую ссылку и, следовательно, являются одним и тем же экземпляром.

Если вы хотите проверить, что содержимое двух разных объектов равно, то вы должны написать код, чтобы сделать это самостоятельно, так или иначе. Это было бы возможно сделать с отражением (тестовый фреймворк MbUnit делает что-то в этом направлении), но с серьезным снижением производительности и хорошим шансом, что он все равно не будет работать так, как вы ожидали, и вы должны осуществить == или Equals и GetHashCode вручную.

3 голосов
/ 29 октября 2009

MSDN имеет хороший пример того, как это сделать:

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

Тогда вы перегружаете == и! =:

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

И не забудьте перегрузить метод GetHash.

Edit:

Я написал следующий быстрый пример использования отражения в сравнении. Это должно быть намного более полным, я мог бы попытаться сделать блог на этом, если люди хотят, чтобы я:

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;
    }
}
2 голосов
/ 29 октября 2009

Правильный подход - перегрузка метода equals класса Tweet в дополнение к оператору ==, как описано здесь .

1 голос
/ 29 октября 2009

Вы можете сравнить свойства, используя отражение:

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;
    }
}
1 голос
/ 29 октября 2009

Будет ли это проверять эквивалентность всех свойств класса Tweet между a и b?

нет

Нет

Если нет, то правильным ли было бы перегрузить оператор == для явной проверки на эквивалентность всех полей?

Вы можете либо перегрузить оператор == , либо перегрузить функцию Equals .

Редактировать

@ Юрий привел хороший пример для вычисления всех непубличных переменных. Поскольку я также написал пример, вот он (мой сравнивает свойства)

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