2009-03-04 2 views
4

Хорошо, поэтому, если я переопределяю Equals, мне нужно переопределить GetHashCode и наоборот.Должен ли я переопределять GetHashCode и Equals в новых классах?

Но я просто задаюсь вопросом: должен ли я всегда переопределять эти два в любом классе? Особенно, если я знаю, что буду использовать их в словаре или подобных сборниках? Пока это fairly straight forward, это все еще дополнительная работа для каждого класса.

Является ли реализация System.Object достаточно плохим, чтобы беспокоиться об этом?

Редактировать: Можете ли вы подробнее рассказать о том, что такое равенство ценностей и справок? Поэтому, если у меня есть две строки (s1 и s2), которые являются «тестами», они равны значению, но поскольку они представляют собой две разные строки, они не являются ссылочными. Хорошо, для строк это не проблема, но каковы обычные ситуации, когда вы захотите использовать Reference или Value Equality?

ответ

6

Насколько я знаю, вам нужно только переопределить их, если вам нужна семантика равенства значений. Реализация System.Object не является «плохим», она просто выполняет только контрольную проверку (которая может быть реализована на этом уровне).

Вкратце: если вам нужно какое-то основанное на значении равенство (равенство, основанное на свойствах класса), то да, отменить. В противном случае, это должно быть более чем хорошо.

EDIT: Вы только нужно переопределить их в случае, описанном выше. Если вы переопределите один из них, вам необходимо переопределить оба по очевидным причинам (они должны быть согласованными и т. Д.). Вы можете переопределить их по каждому классу по другим причинам, указанным в других ответах (например, производительность в алгоритмах, использующих хэш-значение, то есть Dictionary ключей и т. Д.), Но вам не нужно, реализация по умолчанию System.Object будет работать правильно ,

EDIT 2: Запрошенная дополнительная информация, поэтому здесь идет. Рассмотрим следующий псевдо-класс:

public class User { 
    private int _id; 
    private string _username; 
    public string Username { get {return _username;}}; 
    // [snip] Whatever other properties we might like to have. 

    public User(string username) { 
     // Initialise our user from a database, or whatever. 
    } 
} 

Как можно заметить, следующий код, может показаться интуитивно:

User foo = new User("me"); 
User bar = new User("me"); 
User baz = foo; 

if (foo.Equals(bar)) { 
    Console.WriteLine("1: Success!"); 
} 
if (foo.Equals(baz)) { 
    Console.WriteLine("2: Success!"); 
} 

Но он будет печатать только:

2: Успех

Почему? foo и bar - это два отдельных экземпляра класса и имеют отдельные ссылки. Ссылка похожа на указатель на C/C++. foo и baz - одна и та же ссылка, потому что одна из них была назначена из другой. Все они имеют одинаковое значение , хотя пользователь назвал «я». Реализация образца стоимости на основе .Equals реализации может быть:

partial class User { 
    public override bool Equals(object b) { 
     if (b == null) return false; 
     if (b.GetType() != this.GetType()) return false; 

     // Now the heavy lifting 
     User other = (User)b; 
     if (other._id == this._id) return true; 
     else return false; 
    } 
} 

Посмотрите, как он проверяет против части свойств класса для определения равенства? Это равенство ценности на работе. Равенство ссылок было бы просто простой проверкой this == b.

2

Только если вы хотите семантику значения.От MSDN:

Для некоторых видов объектов, то желательно иметь Equals тест на значение равенства вместо ссылочной равенства. Такие реализации Equals возвращают true, если два объекта имеют одинаковое значение, даже если они не совпадают. Определение того, что составляет значение объекта , зависит от разработчика типа , но обычно это часть или все данные , хранящиеся в переменных экземпляра объекта. Например, значение строки основано на символах строки; метод Equals от класс String возвращает true для любого двух экземпляров строки, которые содержат точно такие же символы в того же порядка.

3

Два метода должны быть Соответствует. Другими словами, если два объекта равны равным, то каждый должен возвращать тот же хэш-код. Это особенно важно в хешированных коллекциях. Чтобы найти объект, который соответствует объекту X в хешированном контейнере, контейнер будет проверять только те элементы для равенства, которые имеют тот же хеш-код, что и X.

+0

Отличная точка. – Alan

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