Что должен возвращать GetHashCode, когда идентификатор объекта равен null?

что из следующего является правильным / лучше, учитывая, что свойство identity может быть null.

public override int GetHashCode()
{
    if (ID == null) {
        return base.GetHashCode();
    }
    return ID.GetHashCode();
}

или

public override int GetHashCode()
{
    if (ID != null) {
        return ID.GetHashCode();
    }
     return 0;
}

обновление 1: обновлен 2-й вариант.

обновление 2: Ниже приведены реализации Equals:

public bool Equals(IContract other)
{
    if (other == null)
        return false;
    if (this.ID.Equals(other.ID)) {
        return true;
    }
    return false;
}

public override bool Equals(object obj)
{
    if (obj == null)
        return base.Equals(obj);
    if (!obj is IContract) {
        throw new InvalidCastException("The 'obj' argument is not an IContract object.");
    } else {
        return Equals((IContract)obj);
    }
}

и ID имеет string тип.

3 ответов


это действительно зависит от того, что вы хотите, чтобы равенство означало - важно то, что два равных объекта возвращают один и тот же хэш-код. Что означает равенство, когда ID равен null? В настоящее время ваш метод Equals будет есть для возврата true, если свойства ID имеют одинаковое значение... но мы не знаем, что он делает, если ID равен null.

если вы на самом деле хочу поведение первой версии, я бы лично использовать:

return ID == null ? base.GetHashCode() : ID.GetHashCode();

EDIT: на основе ваш метод Equals, похоже, вы можете сделать свой метод GetHashCode:

return ID == null ? 0 : ID.GetHashCode();

обратите внимание, что ваш Equals(IContract other) метод также может выглядеть так:

return other != null && object.Equals(this.ID, other.ID);

ваша текущая реализация фактически создаст исключение, если this.ID равно null...

кроме того,Equals(object) метод неверен - вы не должны бросать исключение, если вам передан неподходящий тип объекта, вы должны просто вернуть false... то же самое если obj равно null. Так что вы можете на самом деле просто использовать:

public override bool Equals(object obj)
{
    return Equals(obj as IContract);
}

Я обеспокоен равенством, основанным на интерфейсе, однако. Обычно два класса разных типов не должны считаться равными, даже если реализуются одни и те же интерфейсы.


можно просто return 0;, вам нужно вернуть тот же хэш-код для тех же значений, и 0 часто не будет возвращен ID.GetHashCode (), поэтому такая хэш-функция может быть довольно хорошо для любых потребностей. Поскольку вы не объединяете никакие значения (например, ID и хэши имен), его довольно четкий ID является определяющим источником хэш-кода, поэтому фиксированный 0 для Null ID звучит разумно.

в противном случае может быть верно, что весь ваш подход к переопределению GetHashCode только с учетом поля ID неверен ( и вы необходимо объединить несколько полей для вычисления хэша из них)

после ваших изменений я могу сказать, что second Equals override имеет слишком много кода, просто замените его на

public override bool Equals(object obj)
{
    return Equals(obj as Contract);
}

ваше переопределение Equals(IContract contract) кажется мне багги, потому что единственное, что определяет контракт, - это ID, и если IContract имеет больше полей, чем ID, это будет плохое переопределение Equals.

PS: На самом деле, если IContract-это интерфейс, вам, вероятно, нужно заменить ваш IEquatable<IContract> к конкретному IEquatable<ClassName> контракт, потому что его будет плохой дизайн, чтобы иметь возможность возвращать, что разные классы, реализующие один и тот же интерфейс, равны, потому что равенство по определению требует проверить, что объекты имеют один и тот же тип на первом этапе проверки равенства (обычно в 99,9% случаев)


возможно, вы хотите что-то вроде этого?

override int GetHashCode()
{
    if (ID != null)
        return ID.GetHashCode();

    return DBNull.Value.GetHashCode();
}

важно то, что два объекта с нулевыми идентификаторами должны считаться равными?