Почему проверка null не выполняется, даже если объект явно инициализирован как null

Я создал пользовательский класс abstract, который, в свою очередь, конечно же, также создал производные классы.

public abstract class AbstractBaseClass
...

public class ChildClass1 : AbstractBaseClass
...

Теперь всякий раз, когда я объявляю, например, AbstractBaseClass baseClass = null и везде, где после этой инициализации следуют нулевые проверки, она всегда терпит неудачу.

if (baseClass == null)
{
    // this block is never reached - condition always evaluates to false
    // let's say AbstractBaseClass baseClass = null is at line 10
    // even if this condition is at line 11, condition still fails
}

Причина, по которой существует нулевая проверка, заключается в том, что существует несколько производных классов, и в каком-то процессе я определяю, какой это будет тип (например, с помощью случаев переключения). И, конечно, есть недопустимые случаи, в которых я ожидаю, что значение будет инициализированным null.

Это действительно странно, и я действительно ожидаю, что нулевая проверка будет оценена как истинная.

Каковы возможные причины, почему это происходит (чтобы я мог добавить больше примеров кода в зависимости от информации, так как весь соответствующий код довольно большой), и как это исправить? Спасибо.

ИЗМЕНИТЬ:

Кроме того, значение отладчика равно null.

О, правильно, как упомянул @taffer, == перегружен для AbstractBaseClass. Вот эта часть и другой соответствующий код:

    protected bool Equals(AbstractBaseClass other)
    {
        return Equals(this.SomeUniqueProperty, other.SomeUniqueProperty);
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj))
        {
            return false;
        }

        if (ReferenceEquals(this, obj))
        {
            return true;
        }

        return obj.GetType() == this.GetType() && this.Equals((AbstractBaseClass)obj);
    }

    public override int GetHashCode()
    {
        return (this.SomeUniqueProperty != null ? this.SomeUniqueProperty.GetHashCode() : 0);
    }

    public static bool operator ==(AbstractBaseClass a, AbstractBaseClass b)
    {
        if (ReferenceEquals(null, a))
        {
            return false;
        }

        return !ReferenceEquals(null, b) && a.Equals(b);
    }

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

person Michael Balser    schedule 19.03.2019    source источник
comment
при использовании отладчика и установке точки останова какое значение на самом деле находится в baseclass?   -  person Denis Schaf    schedule 19.03.2019
comment
покажите нам dotnetfiddle.net   -  person TheGeneral    schedule 19.03.2019
comment
Когда я смотрю значение, оно равно нулю, поэтому я действительно смущен :(   -  person Michael Balser    schedule 19.03.2019
comment
Вы перекомпилировали свой проект?   -  person HimBromBeere    schedule 19.03.2019
comment
Покажите воспроизводимый пример. Это может быть что угодно. Например, перегружен ли оператор ==?   -  person György Kőszeg    schedule 19.03.2019
comment
@HimBromBeere да, я уже много раз перестраивал решение. Кроме того, эта проверка нуля выполняется во многих местах и ​​в настоящее время нарушает логику приложения.   -  person Michael Balser    schedule 19.03.2019
comment
@MichaelRandall Я пытался воспроизвести только с помощью простого кода, но проверка нуля прошла успешно :( dotnetfiddle.net/ShbVT1   -  person Michael Balser    schedule 19.03.2019
comment
Это потому, что вы не можете создать экземпляр абстрактного класса, что произойдет, если вы выполните проверку if (baseClass == default (BaseClass))   -  person Daniel Loudon    schedule 19.03.2019
comment
@taffer да, я забыл об этом, сейчас я отредактировал сообщение, чтобы отразить дополнительный код.   -  person Michael Balser    schedule 19.03.2019
comment
@MichaelRandall теперь я смог воспроизвести фактический результат с обновленным кодом. dotnetfiddle.net/rXrojC   -  person Michael Balser    schedule 19.03.2019
comment
Зачем вам перегружать оператор == таким неинтуитивным способом? Абстракции, такие как перегрузка операторов, могут использоваться для того, чтобы сделать код кратким и элегантным, но это явный пример того, как можно выстрелить себе в ногу.   -  person dumetrulo    schedule 19.03.2019
comment
Этот фрагмент кода уже устарел. Насколько я помню, это может быть комбинация сгенерированного Resharper кода и копирования + вставки. Теперь это имеет смысл.   -  person Michael Balser    schedule 19.03.2019
comment
@RufusL это определенно приведет к исключению stackoverflowexception.   -  person Michael Balser    schedule 19.03.2019


Ответы (1)


Ваша перегрузка == неверна, поскольку вы возвращаете false, если a имеет значение null, игнорируя тот факт, что b также может быть null.

Что вам нужно сделать, так это вернуть true, если оба равны null или если a равно b:

public static bool operator ==(AbstractBaseClass a, AbstractBaseClass b)
{
    var isANull = ReferenceEquals(null, a);
    var isBNull = ReferenceEquals(null, b)
    return (isANull && isBNull) || a?.Equals(b) ?? false;
}

Примечание. Если a равно нулю, а b нет, оператор .? вернет значение null, а оператор ?? вернет false.

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

public static bool operator ==(AbstractBaseClass a, AbstractBaseClass b)
{
    return a?.Equals(b) ?? ReferenceEquals(null, b);
}

если a равно нулю, вернуть true, если b также равно нулю. если a не равно нулю, вернуть результат a.Equals(b).

В случае, если a не равно null, а b равно, ваш метод Equals должен возвращать false:

protected bool Equals(AbstractBaseClass other)
{
    return other != null 
        ? Equals(this.SomeUniqueProperty, other.SomeUniqueProperty) 
        : false;
}
person Zohar Peled    schedule 19.03.2019