Результат вызова IEquatable <T>.Equals (T obj), когда это == null и obj == null? - PullRequest
8 голосов
/ 11 ноября 2011

Что должны IEquatable<T>.Equals(T obj) делать, когда this == null и obj == null?

1) Этот код генерируется компилятором F # при реализации IEquatable<T>. Вы можете видеть, что он возвращает true, когда оба объекта null:

    public sealed override bool Equals(T obj)
    {
        if (this == null)
        {
            return obj == null;
        }
        if (obj == null)
        {
            return false;
        }

        // Code when both this and obj are not null.
    }

2) Аналогичный код можно найти в вопросе " в IEquatable реализации необходима проверка ссылок " или в вопросе " Есть ли полная ссылка на IEquatable реализацию? ». Этот код возвращает false, когда оба объекта null.

    public sealed override bool Equals(T obj)
    {
        if (obj == null)
        {
            return false;
        }

        // Code when obj is not null.
    }

3) Последний вариант - сказать, что поведение метода не определено, когда this == null.

Ответы [ 7 ]

9 голосов
/ 11 ноября 2011

Леппи прав. Просто чтобы уточнить его ответ (и подтвердить его подозрение, что F # не гарантирует this != null): дискриминированные союзы могут быть помечены атрибутом [<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>], позволяющим случаям быть представленными значением null. Option<'T> это такой тип. Случай None представляется нулевым во время выполнения. (None : option<int>).Equals(None) синтаксически допустим. Вот забавный пример:

[<CompilationRepresentation(CompilationRepresentationFlags.UseNullAsTrueValue)>]
type Maybe<'T> =
  | Just of 'T
  | Nothing
  [<CompilationRepresentation(CompilationRepresentationFlags.Instance)>]
  member this.ThisIsNull() = match this with Nothing -> true | _ -> false

Декомпиляция ThisIsNull с отражателем показывает

public bool ThisIsNull()
{
    return (this == null);
}

И результат:

Nothing.ThisIsNull() //true
3 голосов
/ 11 ноября 2011

Причина, по которой F # делает это (я подозреваю), чтобы оптимизировать пустые списки как null.

Добавление этой проверки позволяет без проблем вызвать метод экземпляра для экземпляра null.

См. мое сообщение в блоге с недавних пор.

В C # это не имеет значения.

Чтобы ответить на вопрос:

Он должен вернуть true, так как оба экземпляра равны null и считаются равными.

1 голос
/ 11 ноября 2011

Для большинства методов я предполагаю неопределенное поведение при вызове с this==null.Это потому, что большинство программистов пишут свой код в предположении, что this!=null, что гарантируется спецификацией C #, если вызывающий код написан на C #.

Вот почему каждый здравомыслящий вызывающий x.Equals(y) должен знатьубедитесь, что x не null, или добавьте ручную проверку null.

В большинстве случаев я бы вообще не стал вызывать Equals, а вместо этого использовал бы EqualityComparer<T>.Default.

1 голос
/ 11 ноября 2011

Если this равно нулю, код не может быть вызван, поэтому не нужно рассматривать этот случай (во всяком случае, в C # есть случаи, когда языки допускают, чтобы у нулевого объекта был разыменован метод, хотя, очевидно, если он внутреннепроверяет любое из своих несуществующих полей, в которых он выдаст ошибку. Рассмотрим:

return x.Equals(y);

Если x равен нулю, мы даже не можем вызвать Equals для проверки на нулевое значение.

Следовательно, нам нужно только рассмотреть:

public bool Equals(T obj)
{
  if(obj == null)
    return false;
  //logic defining equality here.
}

Когда возникает вероятность того, что оба объекта имеют нулевое значение, это когда мы исследуем их из статического переопределения оператора == или из IEqualityComparer<T>реализация:

public bool Equals(T x, T y)
{
  if(x == null)
    return y == null;
  if(y == null)
    return false;
  //logic defining equality here.
}

Обратите внимание, что здесь полезный ярлык, если равенство может быть длинным для определения (например, сравнение длинных строк), тогда мы можем воспользоваться тем фактом, что идентичность влечет за собой равенство - то есть что-то всегда равнодаже Айн Рэнд мог бы понять это;) Существуют также алгоритмы, которые делают сравнение элемента с самим собой довольно распространенным, что делает этот ярлык хорошо стоящим.ЛУДИНГ.В этом случае сравнение идентификаторов уже включает проверку того, что оба значения равны нулю, поэтому мы пропускаем это снова:

public bool Equals(T x, T y)
{
  if(ReferenceEquals(x, y))
    return true;
  if(x == null || y == null)
    return false;
  //logic defining equality here.
}
0 голосов
/ 11 ноября 2011

Если это == null, вы получите исключение времени выполнения, вызывающее Equals () для этого объекта.

0 голосов
/ 11 ноября 2011
0 голосов
/ 11 ноября 2011

Я бы определенно выбрал вариант 1:

    if (this == null)
    {
        return obj == null;
    }
    if (obj == null)
    {
        return false;
    }

нулевой объект всегда равен нулевому объекту.

...