Equals, GetHashCode, EqualityComparers и нечеткое равенство - PullRequest
3 голосов
/ 16 июля 2010

Для объекта со свойствами A, B, C, D, StartDate и EndDate, если бы я хотел реализовать что-то, где любые два объекта равны, если они имеют идентичные A, B и C и перекрывающийся диапазон дат, как это будет сделано

Я пытался создать EqualityComparer, например,

    public override bool Equals(RateItem x, RateItem y)
    {
        bool equal = true;
        if ((x.A != y.A || x.B != y.B || x.C != y.C ||
            (x.StartDate < y.StartDate && x.EndDate <= y.StartDate) ||
            (x.StartDate > y.StartDate && y.EndDate <= x.StartDate)))
        { equal = false; }
        return equal;
    }

Но кажется, что во многих местах фреймворка игнорируется Equals и используется GetHashCode, а документация по этому вопросу вообще не ясна. Когда я иду, чтобы реализовать GetHashCode, я не знаю, как заставить HashCodes получить то же самое, не игнорируя даты.

Чтобы сделать его немного более конкретным, это связано с управлением проектами и ставками. Я хочу реализовать бизнес-правило, согласно которому один и тот же человек в одном и том же проекте в одной роли не может иметь разные ставки в течение одного и того же периода времени. Таким образом, Боб на Project DeathMarch в роли администратора баз данных может иметь только одну эффективную ставку счета в любой момент времени, чтобы регистрировать свое время. Если ему нужно было пройти несколько часов в роли аналитика QA с другой скоростью в течение того же периода времени, это нормально. Это массивная ранее существовавшая система, поэтому изменение структуры доменного объекта не вариант.

Ответы [ 3 ]

4 голосов
/ 16 июля 2010

Это невозможно.

Равенство в .Net должно быть переходным, что означает, что если a == b и b == c, то a == c.

1 голос
/ 16 июля 2010

Это возможно. Единственное правило для GetHashCode заключается в том, что A.GetHashCode () должен быть равен B.GetHashCode (), если A == B. Противоположно, если A == B A.GetHashCode () == B.GetHashCode () не должен быть правда.

Таким образом, вы можете просто сделать GetHashCode следующим образом:

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

GetHashCode не для идентификации! Используется для группировки «похожих» объектов.

Доказательство:

string a = "a";
string b = "EUKCnPMLpp";
Console.WriteLine("a = '{0}', b = '{1}', Same = {2}", a, b, a == b);
Console.WriteLine("a.GetHashCode() = {0}, b.GetHashCode() = {1}, Same = {2}", a.GetHashCode(), b.GetHashCode(), a.GetHashCode() == b.GetHashCode());
0 голосов
/ 16 июля 2010

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

Из документации:

"Но достаточно ли для Hashtable определения, что они являются идентичными объектами? К сожалению, нет. Если Hashtable находитдва объекта с одинаковым хешем, он вызывает их метод Equals, чтобы увидеть, действительно ли два объекта равны. Опять же, реализация Object.Equals по умолчанию вернет false, если два объекта - два разных экземпляра одного и того же класса.Также необходимо добавить переопределение метода Equals в наш класс.

...