Переопределение GetHashCode для изменяемых объектов?

Вы можете попробовать удалить объединение, чтобы сначала удалить данные из таблицы job_parts, а затем таблицу деталей

$delQuery = "DELETE FROM job_parts, parts
INNER JOIN parts ON parts.part_id = job_parts.part_id
WHERE parts.part_id = '$part_id'";

Для получения дополнительной информации, пожалуйста, уделите некоторое время, чтобы прочитать MySQL Delete Join Article

57
задан Wai Ha Lee 8 October 2015 в 15:17
поделиться

5 ответов

How does that work if the fields that it's based on are mutable?

It doesn't in the sense that the hash code will change as the object changes. That is a problem for all of the reasons listed in the articles you read. Unfortunately this is the type of problem that typically only show up in corner cases. So developers tend to get away with the bad behavior.

Also what if I do want dictionary lookups etc to be based on reference equality not my overridden Equals?

As long as you implement an interface like IEquatable this shouldn't be a problem. Most dictionary implementations will choose an equality comparer in a way that will use IEquatable over Object.ReferenceEquals. Even without IEquatable, most will default to calling Object.Equals() which will then go into your implementation.

Basically in most of the executing code I want reference equality and I always use == and I'm not overriding that.

If you expect your objects to behave with value equality you should override == and != to enforce value equality for all comparisons. Users can still use Object.ReferenceEquals if they actually want reference equality.

I used to assume that the framework always uses == and not Equals to compare things

What the BCL uses has changed a bit over time. Now most cases which use equality will take an IEqualityComparer instance and use it for equality. In the cases where one is not specified they will use EqualityComparer.Default to find one. At worst case this will default to calling Object.Equals

22
ответ дан 26 November 2019 в 16:55
поделиться

Если у вас есть изменяемый объект, нет особого смысла переопределять метод GetHashCode, поскольку вы не можете его использовать. Например, он используется в коллекциях Dictionary и HashSet для помещения каждого элемента в корзину. Если вы измените объект, пока он используется в качестве ключа в коллекции, хэш-код больше не будет соответствовать сегменту, в котором находится объект, поэтому коллекция не будет работать должным образом, и вы никогда не сможете найти объект снова.

Если если вы хотите, чтобы поиск не использовал метод класса GetHashCode или Equals , вы всегда можете предоставить свою собственную реализацию IEqualityComparer для использования вместо этого при создании Словарь .

Метод Equals предназначен для равенства значений,

6
ответ дан 26 November 2019 в 16:55
поделиться

Wow, that's actually several questions in one :-). So one after the other:

it's been cited that the value of GetHashCode should never change over the lifetime of the object. How does that work if the fields that it's based on are mutable?

This common advice is meant for the case where you want to use your object as a key in a HashTable/dictionary etc. . HashTables usually require the hash not to change, because they use it to decide how to store & retrieve the key. If the hash changes, the HashTable will probably no longer find your object.

To cite the docs of Java's Map interface:

Note: great care must be exercised if mutable objects are used as map keys. The behavior of a map is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is a key in the map.

In general it's a bad idea to use any kind of mutable object as a key in a hash table: It's not even clear what should happen if a key changes after it's been added to the hash table. Should the hash table return the stored object via the old key, or via the new key, or via both?

So the real advice is: Only use immutable objects as keys, and make sure their hashcode never changes either (which is usually automatic if the object is immutable).

Also what if I do want dictionary lookups etc to be based on reference equality not my overridden Equals?

Well, find a dictionary implementation that works like that. But the standard library dictionaries use the hashcode&Equals, and there's no way to change that.

I'm primarily overriding Equals for the ease of unit testing my serialization code which I assume serializing and deserializing (to XML in my case) kills the reference equality so I want to make sure at least it's correct by value equality. Is this bad practice to override Equals in this case?

No, I'd find that perfectly acceptable. However, you should not use such objects as keys in a dictionary/hashtable, as they're mutable. See above.

4
ответ дан 26 November 2019 в 16:55
поделиться

The underlying topic here is how to best uniquely identify objects. You mention serialization/deserialization which is important because referential integrity is lost in that process.

The short answer, Is that objects should be uniquely identified by the smallest set of immutable fields that can be used to do so. These are the fields you should use when overrideing GetHashCode and Equals.

For testing it's perfectly reasonable to define whatever assertions you need, usually these are not defined on the type itself but rather as utility methods in the test suite. Maybe a TestSuite.AssertEquals(MyClass, MyClass) ?

Note that GetHashCode and Equals should work together. GetHashCode should return the same value for two objects if they are equal. Equals should return true if and only if two objects have the same hash code. (Note that it's possible that two object may not be equal but may return the same hash code). There are plenty of webpage that tackle this topic head-on, just google away.

1
ответ дан 26 November 2019 в 16:55
поделиться

Я не знаю, что C # является относительным новичком по отношению к нему, но в Java, если вы переопределите equals (), вам также нужно переопределить hashCode () для поддержания контракта между ними ( и наоборот) ... И в java тоже есть уловка 22; в основном заставляет вас использовать неизменяемые поля ... Но это проблема только для классов, которые используются в качестве хеш-ключа, а в Java есть альтернативные реализации для всех коллекций на основе хешей ... что, возможно, не так быстро, но они действительно эффективно позволяют использовать изменяемый объект в качестве ключа ... он (обычно) хмурится как "плохой дизайн".

И я чувствую побуждение указать, что эта фундаментальная проблема вечна ... так как Адам был мальчиком.

Я работал над кодом Fortran, который старше меня (я ' m 36), который прерывается при изменении имени пользователя (например, когда девушка выходит замуж или разводится ;-) ... Таким образом, инженерное решение. Принятое решение было: «Метод» GetHashCode запоминает ранее вычисленный hashCode, пересчитывает hashCode ( т.е. виртуальный маркер isDirty), и если ключевые поля изменились, он возвращает null. Это приводит к тому, что кеш удаляет «грязного» пользователя (путем вызова другого GetPreviousHashCode), а затем кеш возвращает значение null, в результате чего пользователь перечитывает данные из базы данных. Интересный и стоящий хак; даже если я сам так говорю; -)

Я уступлю изменчивость (желательно только в угловых случаях) для доступа O (1) (желательно во всех случаях). Добро пожаловать в инжиниринг; страна осознанного компромисса.

Ура. Кит.

«Метод» GetHashCode запоминает ранее вычисленный hashCode, пересчитывает hashCode (т.е. виртуальный маркер isDirty), и, если ключевые поля изменились, он возвращает null. Это приводит к тому, что кеш удаляет «грязного» пользователя (путем вызова другого GetPreviousHashCode), а затем кеш возвращает значение null, в результате чего пользователь перечитывает данные из базы данных. Интересный и стоящий хак; даже если я сам так говорю; -)

Я уступлю изменчивость (желательно только в угловых случаях) для доступа O (1) (желательно во всех случаях). Добро пожаловать в инжиниринг; страна осознанного компромисса.

Ура. Кит.

«Метод» GetHashCode запоминает ранее вычисленный hashCode, пересчитывает hashCode (т.е. виртуальный маркер isDirty), и, если ключевые поля изменились, он возвращает null. Это приводит к тому, что кеш удаляет «грязного» пользователя (путем вызова другого GetPreviousHashCode), а затем кеш возвращает значение null, в результате чего пользователь перечитывает данные из базы данных. Интересный и стоящий хак; даже если я сам так говорю; -)

Я уступлю изменчивость (желательно только в угловых случаях) для доступа O (1) (желательно во всех случаях). Добро пожаловать в инжиниринг; страна осознанного компромисса.

Ура. Кит.

Это приводит к тому, что кеш удаляет «грязного» пользователя (путем вызова другого GetPreviousHashCode), а затем кеш возвращает значение null, в результате чего пользователь перечитывает данные из базы данных. Интересный и стоящий хак; даже если я сам так говорю; -)

Я уступлю изменчивость (желательно только в угловых случаях) для доступа O (1) (желательно во всех случаях). Добро пожаловать в инжиниринг; страна осознанного компромисса.

Ура. Кит.

Это приводит к тому, что кеш удаляет «грязного» пользователя (путем вызова другого GetPreviousHashCode), а затем кеш возвращает значение null, в результате чего пользователь перечитывает данные из базы данных. Интересный и стоящий хак; даже если я сам так говорю; -)

Я уступлю изменчивость (желательно только в угловых случаях) для доступа O (1) (желательно во всех случаях). Добро пожаловать в инжиниринг; страна осознанного компромисса.

Ура. Кит.

2
ответ дан 26 November 2019 в 16:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: