Перегрузка GetHashCode и оператора равенства с использованием оператора XOR для перечислений

У меня есть следующий класс, который является частью пакета статического анализа.

  • Объект MetricKey используется как ключ словаря.
  • Decision, MetricUnit и Portfolio — все перечисления.

Мне пришлось переопределить оператор равенства (==), чтобы заставить работать сопоставление ключей словаря. Я использовал руководство по адресу http://msdn.microsoft.com/en-us/library/ms173147.aspx. В руководстве говорилось, что я должен перегрузить метод GetHashCode, который я сделал, но я не понимаю последствий приведения моих перечислений к целым числам для операции XOR (^). Верно ли то, что я сделал, или я получу конфликтующие хэш-коды из-за перекрытия моих целочисленных значений перечисления?:

public class MetricKey
{
    public MetricKey(Decision decision, MetricUnit metricUnit, Portfolio portfolio)
    {
        Decision = decision;
        Unit = metricUnit;
        Portfolio = portfolio;
    }

    public Decision Decision { get; private set; }
    public MetricUnit Unit { get; private set; }
    public Portfolio Portfolio { get; private set; }

    public static bool operator == (MetricKey a, MetricKey b)
    {
        if (ReferenceEquals(a, b))
            return true;
        if (((object) a == null) || ((object) b == null))
            return false;
        return a.Decision == b.Decision && a.Unit == b.Unit && a.Portfolio == b.Portfolio;
    }

    public static bool operator != (MetricKey a, MetricKey b)
    {
        return !(a == b);
    }

    public override bool Equals(System.Object obj)
    {
        if (obj == null)
            return false;
        var metricKey = obj as MetricKey;
        if ((System.Object) metricKey == null)
            return false;
        return Decision == metricKey.Decision && Unit == metricKey.Unit && Portfolio == metricKey.Portfolio;
    }

    public bool Equals(MetricKey metricKey)
    {
        if ((object) metricKey == null)
            return false;
        return Decision == metricKey.Decision && Unit == metricKey.Unit && Portfolio == metricKey.Portfolio;
    }

    public override int GetHashCode()
    {
        return (int)Decision ^ (int)Unit ^ (int)Portfolio;
    }
}

person grenade    schedule 23.02.2010    source источник


Ответы (1)


Нет ничего плохого в приведении к int - однако я бы на самом деле избегал xor - легко создавать коллизии с вероятными значениями перечислений (1,2,3 и т. д.). Обратите внимание, что коллизии ничего не ломают, но могут сделать вещи дороже. Я мог бы использовать что-то вроде (выбор наугад, вдохновленный компилятором C#, обрабатывающим анонимные типы):

int num = -1962473570;
num = (-1521134295 * num) + (int)Decision;
num = (-1521134295 * num) + (int)Unit;
return (-1521134295 * num) + (int)Portfolio;
person Marc Gravell    schedule 23.02.2010
comment
(обратите внимание, что если это было что-то более сложное, чем перечисление, вы должны вызвать для него .GetHashCode() (сначала проверив значение null) - как это бывает, GetHashCode() для int возвращает это, так что не так много смысла ;-p) - person Marc Gravell; 23.02.2010