Этот вопрос вытекает из обсуждения кортежи.
Я начал думать о хеш-коде, который должен быть у кортежа. Что, если мы примем класс KeyValuePair как кортеж? Он не переопределяет метод GetHashCode(), поэтому, вероятно, он не будет знать о хэш-кодах своих "потомков"... Таким образом, во время выполнения будет вызываться Object.GetHashCode(), который не знает о структура реального объекта.
Затем мы можем создать два экземпляра некоторого ссылочного типа, которые на самом деле равны Equal из-за перегруженных функций GetHashCode() и Equals(). И используйте их как «детей» в кортежах, чтобы «обмануть» словарь.
Но это не работает! Время выполнения каким-то образом выясняет структуру нашего кортежа и вызывает перегруженный GetHashCode нашего класса!
Как это работает? Какой анализ делает Object.GetHashCode()?
Может ли это повлиять на производительность в каком-то плохом сценарии, когда мы используем какие-то сложные ключи? (наверное, невозможный сценарий... но все же)
Рассмотрим этот код в качестве примера:
namespace csharp_tricks
{
class Program
{
class MyClass
{
int keyValue;
int someInfo;
public MyClass(int key, int info)
{
keyValue = key;
someInfo = info;
}
public override bool Equals(object obj)
{
MyClass other = obj as MyClass;
if (other == null) return false;
return keyValue.Equals(other.keyValue);
}
public override int GetHashCode()
{
return keyValue.GetHashCode();
}
}
static void Main(string[] args)
{
Dictionary<object, object> dict = new Dictionary<object, object>();
dict.Add(new KeyValuePair<MyClass,object>(new MyClass(1, 1), 1), 1);
//here we get the exception -- an item with the same key was already added
//but how did it figure out the hash code?
dict.Add(new KeyValuePair<MyClass,object>(new MyClass(1, 2), 1), 1);
return;
}
}
}
Обновление Я думаю, что нашел объяснение этому, как указано ниже в моем ответе. Основными результатами его являются:
- Будьте осторожны со своими ключами и их хэш-кодами :-)
- Для сложных ключей словаря вы должны правильно переопределить Equals() и GetHashCode().