3

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

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

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

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

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

UPDATE: Из первых двух ответов, я прав в предположении:

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

UPDATE # 2: Юрий сделал замечание, что можно делать проверку эквивалентности в свойствах в операторе == с отражения. Как это может быть сделано? Не могли бы вы дать мне пример кода? Благодаря!

+1

Перед тем, как перегрузить оператор, считаю это: Моим обычным эмпирическим правило, когда речь идет о перегрузке операторов задает этот вопрос себе: «Есть ли общая смысл? Кто-нибудь другой разработчик сразу узнает, что делает оператор, даже не глядя на реализацию (код)? " Если ответ не «100% да», не делайте этого. Если это так, то, безусловно, пойти на это. –

ответ

3

MSDN имеет хорошую example о том, как это сделать:

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

+1 для решения отражения (это второй раз, когда вы отправляете минутой передо мной :) – Amirshk

+0

И как бы вы реализовали GetHashCode(), используя такой подход на основе отражения? –

+1

@John: Почему бы не использовать отражение в сочетании с ответом Джона Скита: http: // stackoverflow.com/вопросы/263400 # 263416 –

2

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

+0

Итак, мне нужно было бы вручную проверить эквивалентность каждого из свойств? Есть ли более быстрый способ сделать это, скажем, в цикле? –

+1

@Maxim: Вы можете использовать отражение, чтобы сравнить все поля. Сколько у вас полей? Следите за SRP. –

+0

Вы можете использовать отражение для запуска функции equals во всех своих внутренних свойствах. – Amirshk

1

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

Нет

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

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

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

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

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

Большое спасибо, это действительно помогает! –

4

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

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

+1

+1 для обозначения последствий производительности и сложности с помощью решения на основе отражения. –

+0

@GraemeF, Производительность мудрая, по-прежнему существует возможность использовать стратегию кэширования с Compiled Expression Trees над getters (или даже IL, если вы действительно это чувствуете), чтобы проверить поля и свойства во время выполнения. Большинство ORM используют этот способ, и он может быть довольно быстрым (хотя и медленнее, чем чистый жесткий диск). – Ehouarn

1

Вы можете сравнить свойства с помощью отражения:

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; 
    } 
} 
Смежные вопросы