Как проверить наличие нулей в перегрузке оператора '==' без бесконечной рекурсии? - PullRequest
105 голосов
/ 16 сентября 2008

Следующее вызовет бесконечную рекурсию для метода перегрузки оператора ==

    Foo foo1 = null;
    Foo foo2 = new Foo();
    Assert.IsFalse(foo1 == foo2);

    public static bool operator ==(Foo foo1, Foo foo2) {
        if (foo1 == null) return foo2 == null;
        return foo1.Equals(foo2);
    }

Как проверить наличие нулей?

Ответы [ 12 ]

130 голосов
/ 16 сентября 2008

Использование ReferenceEquals:

Foo foo1 = null;
Foo foo2 = new Foo();
Assert.IsFalse(foo1 == foo2);

public static bool operator ==(Foo foo1, Foo foo2) {
    if (object.ReferenceEquals(null, foo1))
        return object.ReferenceEquals(null, foo2);
    return foo1.Equals(foo2);
}
18 голосов
/ 16 сентября 2008

Приведение к объекту в методе перегрузки:

public static bool operator ==(Foo foo1, Foo foo2) {
    if ((object) foo1 == null) return (object) foo2 == null;
    return foo1.Equals(foo2);
}
7 голосов
/ 16 сентября 2008

Используйте <a href="http://msdn.microsoft.com/en-us/library/system.object.referenceequals(VS.80).aspx" rel="noreferrer">ReferenceEquals</a>. Из форумов MSDN :

public static bool operator ==(Foo foo1, Foo foo2) {
    if (ReferenceEquals(foo1, null)) return ReferenceEquals(foo2, null);
    if (ReferenceEquals(foo2, null)) return false;
    return foo1.field1 == foo2.field2;
}
4 голосов
/ 17 сентября 2008

Если я переопределил bool Equals(object obj) и хочу, чтобы операторы == и Foo.Equals(object obj) возвращали один и тот же ответ, я обычно реализую оператор != так:

public static bool operator ==(Foo foo1, Foo foo2) {
  return object.Equals(foo1, foo2);
}
public static bool operator !=(Foo foo1, Foo foo2) {
  return !object.Equals(foo1, foo2);
}

Оператор == затем, после выполнения всех нулевых проверок для меня, в итоге вызовет foo1.Equals(foo2), который я переопределил, чтобы выполнить фактическую проверку, если два равны.

4 голосов
/ 16 сентября 2008

Попробуйте Object.ReferenceEquals(foo1, null)

В любом случае, я бы не рекомендовал перегружать оператор ==; его следует использовать для сравнения ссылок и использовать Equals для «семантических» сравнений.

2 голосов
/ 05 июня 2017

Если вы используете C # 7 или более позднюю версию, вы можете использовать поиск по шаблону с нулевой константой:

public static bool operator==(Foo foo1, Foo foo2)
{
    if (foo1 is null)
        return foo2 is null;
    return foo1.Equals(foo2);
}

Это дает вам немного более аккуратный код, чем тот, который вызывает объект .ReferenceEquals (foo1, null)

1 голос
/ 16 декабря 2012

Мой подход - сделать

(object)item == null

, на который я полагаюсь на собственный оператор равенства object, который не может пойти не так. Или пользовательский метод расширения (и перегрузка):

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null;
}

public static bool IsNull<T>(this T? obj) where T : struct
{
    return !obj.HasValue;
}

или для обработки большего количества случаев может быть:

public static bool IsNull<T>(this T obj) where T : class
{
    return (object)obj == null || obj == DBNull.Value;
}

Ограничение предотвращает IsNull для типов значений. Теперь это так же сладко, как звонить

object obj = new object();
Guid? guid = null; 
bool b = obj.IsNull(); // false
b = guid.IsNull(); // true
2.IsNull(); // error

, что означает, что у меня есть один непротиворечивый / не подверженный ошибкам стиль проверки на наличие нулей повсюду. Я также обнаружил, что (object)item == null очень очень очень немного быстрее, чем Object.ReferenceEquals(item, null), но только в том случае, если это имеет значение (в настоящее время я работаю над чем-то, что я должен микро-оптимизировать все!).

Чтобы ознакомиться с полным руководством по реализации проверок на равенство, см. Что такое «Лучшая практика» для сравнения двух экземпляров ссылочного типа?

0 голосов
/ 07 февраля 2019

Существует на самом деле более простой способ проверки null в этом случае:

if (foo is null)

Вот и все!

Эта функция была введена в C # 7

0 голосов
/ 16 июля 2018

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

В тех случаях, когда это делается для поддержки объектов-значений, я нахожу новую запись удобной и хочу убедиться, что есть только одно место для сравнения. Также использование Object.Equals (A, B) упрощает нулевые проверки.

Это приведет к перегрузке ==,! =, Equals и GetHashCode

    public static bool operator !=(ValueObject self, ValueObject other) => !Equals(self, other);
    public static bool operator ==(ValueObject self, ValueObject other) => Equals(self, other);
    public override bool Equals(object other) => Equals(other as ValueObject );
    public bool Equals(ValueObject other) {
        return !(other is null) && 
               // Value comparisons
               _value == other._value;
    }
    public override int GetHashCode() => _value.GetHashCode();

Для более сложных объектов добавьте дополнительные сравнения в Equals и более богатый GetHashCode.

0 голосов
/ 02 августа 2017

Статический Equals(Object, Object) метод указывает, равны ли два объекта, objA и objB. Это также позволяет вам проверять объекты, чье значение равно null на равенство. Он сравнивает objA и objB на равенство следующим образом:

  • Определяет, представляют ли два объекта одну и ту же ссылку на объект. Если они это делают, метод возвращает true. Этот тест эквивалентен вызову метода ReferenceEquals. Кроме того, если objA и objB равны null, метод возвращает true.
  • Определяет, является ли objA или objB null. Если это так, он возвращает false. Если два объекта не представляют одну и ту же ссылку на объект и ни один из них не является null, он вызывает objA.Equals(objB) и возвращает результат. Это означает, что если objA переопределяет метод Object.Equals(Object), вызывается это переопределение.

.

public static bool operator ==(Foo objA, Foo objB) {
    return Object.Equals(objA, objB);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...