2013-07-17 2 views

ответ

6

компаратором равенство по умолчанию для ссылочных типов является равенство ссылок, который возвращает только true если две объектные ссылки указывают на же экземпляра (т.е. были созданы с помощью одного new заявления). Это отличается от типов значений, которые проверяют для равенства значений и возвращают true, если все их поля данных равны (например, два в вашем случае). Дополнительная информация: Equality Comparisons (C# Programming Guide).

Если вы хотите изменить это поведение, вам необходимо реализовать общий интерфейс IEquatable<T> для вашего типа, чтобы он сравнивал свойства экземпляров для равенства. Оператор Distinct впоследствии автоматически подберет эту реализацию и даст ожидаемые результаты.

Редактировать: Вот пример реализации IEquatable<Person> для вашего класса:

public class Person : IEquatable<Person> 
{ 
    public int Id { get; set; } 
    public int Name { get; set; } 

    public bool Equals(Person other) 
    { 
     if (other == null) 
      return false; 

     return Object.ReferenceEquals(this, other) || 
      this.Id == other.Id && 
      this.Name == other.Name; 
    } 

    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as Person); 
    } 

    public override int GetHashCode() 
    { 
     int hash = this.Id.GetHashCode(); 
     if (this.Name != null) 
      hash ^= this.Name.GetHashCode(); 
     return hash; 
    } 
} 

С guidelines на переопределение == и != операторы (курсив наш):

По умолчанию оператор == проверяет ссылочное равенство, определяя, указывают ли две ссылки на один и тот же объект. Поэтому для получения этой функциональности ссылочные типы не должны реализовывать оператор ==. Если тип неизменен, то есть данные, которые содержатся в экземпляре, не могут быть изменены, оператор перегрузки == для сравнения равенства значений вместо ссылочного равенства может быть полезным, поскольку в качестве неизменяемых объектов их можно считать одинаковыми до тех пор, пока они имеют одинаковую ценность. Не рекомендуется переопределять оператор == в неизменяемых типах.

+0

Не могли бы вы привести пример IEquatable с кодом, отредактировав ваш ответ? Или мне будет достаточно ссылки. спасибо –

3

Это потому, что вы не преодолели равенства в своем классе. Прямо сейчас, когда вы используете разные, он проверяет ссылочное равенство. Чтобы изменить это, вам нужно переопределить несколько вещей: operator==, Equals(), а для получения лучших результатов GetHashCode().

Это, как я хотел бы сделать это:

public static bool operator ==(Person one, Person two) 
{ 
    return one.Id == two.Id && one.Name == two.Name; 
} 
public static override bool Equals(Person one, Person two) 
{ 
    return one == two; 
} 
public override bool Equals(object obj) 
{ 
    return obj is Person && ((Person)obj) == this; 
} 
public bool Equals(Person other) 
{ 
    return other == this; 
} 
public override int GetHashCode() 
{ 
    unchecked 
    { 
     return 17 * Id * 31 * Name.GetHashCode(); 
    } 
} 

Кроме того, вы можете реализовать интерфейс IEquatable<T> (я сделал выше, все, что вам нужно, чтобы убедиться, что вы добавляете : IEquatable<Person> в конце вашего заголовок класса (class Person и т. д.)), а затем это будет реализовано.

+1

Действительно ли это лучший способ пойти? Почему бы просто не реализовать IEquatable? – Kippie

+0

@ Kippie Потому что обычно можно ожидать, что он будет переоценен. –

Смежные вопросы