Вопрос по c#, .net – GetHashCode () проблема с использованием XOR

9

Насколько я понимаю, обычно предполагается, что вы используете xor с GetHashCode () для создания целого числа, чтобы идентифицировать ваши данные по их значению (а не по ссылке). Вот простой пример:

<code>class Foo
{
    int m_a;
    int m_b;

    public int A
    {
        get { return m_a; }
        set { m_a = value; }
    }

    public int B
    {
        get { return m_b; }
        set { m_b = value; }
    }

    public Foo(int a, int b)
    {
        m_a = a;
        m_b = b;
    }

    public override int GetHashCode()
    {
        return A ^ B;
    }

    public override bool Equals(object obj)
    {
        return this.GetHashCode() == obj.GetHashCode();
    }
}
</code>

Идея заключается в том, что я хочу сравнить один экземпляр Foo с другим на основе значения свойств A и B. Если Foo1.A == Foo2.A и Foo1.B == Foo2.B, то мы имеем равенство.

Here's the problem:

<code>Foo one = new Foo(1, 2);
Foo two = new Foo(2, 1);

if (one.Equals(two)) { ... }  // This is true!
</code>

Они оба выдают значение 3 для GetHashCode (), в результате чего Equals () возвращает true. Очевидно, это тривиальный пример, и только с двумя свойствами я мог бы просто сравнить отдельные свойства в методе Equals (). Однако с более сложным классом это быстро вышло бы из-под контроля.

Я знаю, что иногда имеет смысл установить хеш-код только один раз и всегда возвращать одно и то же значение. Однако для изменчивых объектов, где необходима оценка равенства, я не думаю, что это разумно.

What's the best way to handle property values that could easily be interchanged when implementing GetHashCode()?

See Also

What is the best algorithm for an overridden System.Object.GetHashCode?

Ваш Ответ

7   ответов
1

public override int GetHashCode()
{
    return A.GetHashCode() ^ B.GetHashCode();         // XOR
}
0

Хэш FNV например.

2

но также помните, что вы не должны использовать хеш-коды в качестве проверки на равенство, поскольку они не гарантируют, что они будут уникальными.

Для тривиального примера, почему это рассмотреть двойной объект. У него больше возможных значений, чем у int, поэтому невозможно иметь уникальный int для каждого двойника. Хеши - это всего лишь первый проход, используемый в ситуациях, таких как словарь, когда вам нужно быстро найти ключ. Путем первого сравнения хешей можно исключить большой процент возможных ключей, и только ключи с соответствующими хешами должны иметь затраты. полной проверки равенства (или другойразрешение столкновений методы).

1

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

Используя простой XOR, вы получите много коллизий. Если вы хотите меньше, используйте некоторые математические функции, которые распределяют значения по разным битам (сдвиги битов, умножение на простые числа и т. Д.).

27

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

Контракт для GetHashCode () включает в себя следующее:

different hashcodes means that objects are definitely not equal same hashcodes means objects might be equal (but possibly might not)

Эндрю Харе предложил мне включить его ответ:

Я бы порекомендовал вам прочитатьэто решение (нашими собственнымиДжон Скитмежду прочим) для "лучше" способ вычисления хеш-кода.

No, the above is relatively slow and doesn't help a lot. Some people use XOR (eg a ^ b ^ c) but I prefer the kind of method shown in Josh Bloch's "Effective Java":

public override int GetHashCode()
{
    int hash = 23;
    hash = hash*37 + craneCounterweightID;
    hash = hash*37 + trailerID;
    hash = hash*37 + craneConfigurationTypeCode.GetHashCode();
    return hash;
}

The 23 and 37 are arbitrary numbers which are co-prime.

The benefit of the above over the XOR method is that if you have a type which has two values which are frequently the same, XORing those values will always give the same result (0) whereas the above will differentiate between them unless you're very unlucky.

Как упоминалось в приведенном выше фрагменте, вы также можете посмотреть наКнига Джошуа Блоха "Эффективная Ява", который содержит хорошую трактовку темы (обсуждение хеш-кода относится и к .NET).

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Jon B
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
1

Переопределить GetHashCode для изменяемых объектов? C # и подумать о реализацииIEquatable<T>

0

поскольку хеш-коды, как правило, являются плохой идеей для сравнения, не лучше ли просто выполнить следующий код или я что-то упустил?

public override bool Equals(object obj)
{
    bool isEqual = false;
    Foo otherFoo = obj as Foo;
    if (otherFoo != null)
    {
        isEqual = (this.A == otherFoo.A) && (this.B == otherFoo.B);
    }
    return isEqual;
}
Error: User Rate Limit Exceeded Jon B

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