Объект C# не равен null, но (myObject! = Null) по-прежнему возвращает false

Мне нужно провести сравнение между объектом и NULL. Когда объект не равен NULL, я заполняю его некоторыми данными.

Вот код:

 if (region != null)
 {
  ....
 }

Это работает, но иногда при зацикливании и зацикливании объект региона НЕ равен нулю (я вижу данные внутри него в режиме отладки). Пошагово при отладке он не входит в оператор IF ... Когда я провожу быстрое наблюдение со следующим выражением: я вижу, что (region == null) возвращает false, AND (region! = Null ) тоже верните false ... почему и как?

Обновлять

Кто-то указывает, что объект был == и! = Перегружен:

    public static bool operator ==(Region r1, Region r2)
    {
        if (object.ReferenceEquals(r1, null))
        {
            return false;
        }
        if (object.ReferenceEquals(r2, null))
        {
            return false;
        }

        return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
    }


    public static bool operator !=(Region r1, Region r2)
    {
        if (object.ReferenceEquals(r1, null))
        {
            return false;
        }
        if (object.ReferenceEquals(r2, null))
        {
            return false;
        }
        return (r1.Cmr.CompareTo(r2.Cmr) != 0 || r1.Id != r2.Id);
    }
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
18
0
61 456
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Иногда это может произойти, когда у вас есть несколько потоков, работающих с одними и теми же данными. В этом случае вы можете использовать блокировку, чтобы они не связывались друг с другом.

Спасибо, но причина в том, что == и! = Не были хорошо перегружены. Но ваш ответ мог быть правильным.

Patrick Desjardins 01.10.2008 03:13
Ответ принят как подходящий

Перегружен ли оператор == и / или! = Для класса объекта региона?

Теперь, когда вы разместили код для перегрузок:

Перегрузки, вероятно, должны выглядеть следующим образом (код взят из сообщений, сделанных Джон Скит и Филип Рик):

public static bool operator ==(Region r1, Region r2)
{
    if (object.ReferenceEquals( r1, r2)) {
        // handles if both are null as well as object identity
        return true;
    }

    if ((object)r1 == null || (object)r2 == null)
    {
       return false;
    }        

    return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
}

public static bool operator !=(Region r1, Region r2)
{
    return !(r1 == r2);
}

Я только что понял, что у меня == и! = Перегружены!

Patrick Desjardins 01.10.2008 02:53

Я думаю, что кто-то ошибся в части! =, Я ​​это проверю! Спасибо за подсказку.

Patrick Desjardins 01.10.2008 02:54

Правильно, перегрузки неправильные - если вы скопируете код или объяснение из моего сообщения ниже, я удалю свой пост

Philip Rieck 01.10.2008 03:04

@Philip Rieck - Готово, хотя я не уверен, что вам нужно удалять свой пост (и я надеюсь, что не испортил логику кода).

Michael Burr 01.10.2008 04:27

Эти перегрузки оператора не работают.

Во-первых, это значительно упрощает жизнь, если! = Реализуется простым вызовом == и инвертированием результата.

Во-вторых, перед проверкой нулевого значения в == должно быть:

if (object.ReferenceEquals(r1, r2))
{
    return true;
}

Хорошо, я сделаю модификацию через несколько минут.

Patrick Desjardins 01.10.2008 03:04

Получается, что эти проверки здесь неправильные:

public static bool operator !=(Region r1, Region r2)
{
    if (object.ReferenceEquals(r1, null))
    {
        return false;
    }
    if (object.ReferenceEquals(r2, null))
    {
        return false;
    }
...

Да - вам нужна дополнительная проверка заранее, чтобы учесть случай, когда r1 и r2 оба равны нулю. Проверьте мой ответ. (Это также оптимизирует случай, когда r1 и r2 не равны нулю, но относятся к одному и тому же объекту.)

Jon Skeet 01.10.2008 03:00

Обе перегрузки неверны

 public static bool operator ==(Region r1, Region r2)
    {
        if (object.ReferenceEquals(r1, null))
        {
            return false;
        }
        if (object.ReferenceEquals(r2, null))
        {
            return false;
        }

        return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
    }

если r1 и r2 равны нулю, первый тест (объект.ReferenceEquals (r1, null)) вернет false, даже если r2 также равно нулю.

пытаться

//ifs expanded a bit for readability
 public static bool operator ==(Region r1, Region r2)
    {
        if ( (object)r1 == null && (object)r2 == null)
        {
           return true;
        }
        if ( (object)r1 == null || (object)r2 == null)
        {
           return false;
        }        
        //btw - a quick shortcut here is also object.ReferenceEquals(r1, r2)

        return (r1.Cmr.CompareTo(r2.Cmr) == 0 && r1.Id == r2.Id);
    }

Это работает !!!!!!!! Спасибо, что вы были бы моим "Принятым ответом", но кто-то другой сначала найдет причину, а вы поймете, как :)

Patrick Desjardins 01.10.2008 03:24

Есть еще одна возможность, что вам нужно щелкнуть значок обновления рядом с параметром, который вы наблюдаете. VS пытается не отставать от производительности, не оценивая каждый оператор / параметр. Прежде чем начинать вносить изменения в нерелевантные места, убедитесь в этом.

Для сравнения на равенство типа "T" перегрузите эти методы:

int GetHashCode() //Overrides Object.GetHashCode
bool Equals(object other) //Overrides Object.Equals; would correspond to IEquatable, if such an interface existed
bool Equals(T other) //Implements IEquatable<T>; do this for each T you want to compare to
static bool operator ==(T x, T y)
static bool operator !=(T x, T y)

Ваш код сравнения для конкретного типа должен быть выполнен в одном месте: типобезопасный интерфейс IEquatable<T>, метод Equals(T other). Если вы сравниваете с другим типом (T2), также реализуйте IEquatable<T2> и поместите код сравнения полей для этого типа в Equals (T2 other).

Все перегруженные методы и операторы должны перенаправлять задачу сравнения на равенство основному типобезопасному методу экземпляра Equals (T other), чтобы поддерживалась чистая иерархия зависимостей и вводились более строгие гарантии на каждом уровне для устранения избыточности и несущественной сложности.

bool Equals(object other)
{
    if (other is T) //replicate this for each IEquatable<T2>, IEquatable<T3>, etc. you may implement
        return Equals( (T)other) ); //forward to IEquatable<T> implementation
    return false; //other is null or cannot be compared to this instance; therefore it is not equal
}

bool Equals(T other)
{
    if ((object)other == null) //cast to object for reference equality comparison, or use object.ReferenceEquals
        return false;
    //if ((object)other == this) //possible performance boost, ONLY if object instance is frequently compared to itself! otherwise it's just an extra useless check
        //return true;
    return field1.Equals( other.field1 ) &&
           field2.Equals( other.field2 ); //compare type fields to determine equality
}

public static bool operator ==( T x, T y )
{
    if ((object)x != null) //cast to object for reference equality comparison, or use object.ReferenceEquals
        return x.Equals( y ); //forward to type-safe Equals on non-null instance x
    if ((object)y != null)
        return false; //x was null, y is not null
    return true; //both null
}

public static bool operator !=( T x, T y )
{
    if ((object)x != null)
        return !x.Equals( y ); //forward to type-safe Equals on non-null instance x
    if ((object)y != null)
        return true; //x was null, y is not null
    return false; //both null
}

Обсуждение:

Предыдущая реализация централизует специфичное для типа (т. Е. Равенство полей) сравнение до конца реализации IEquatable<T> для этого типа. Операторы == и != имеют параллельную, но противоположную реализацию. Я предпочитаю иметь одну ссылку на другую, так что есть дополнительный вызов метода для зависимого. Если оператор != просто будет вызывать оператора ==, а не предлагать оператора с такой же производительностью, то вы можете просто использовать !(obj1 == obj2) и избежать дополнительного вызова метода. Сравнение с самим собой исключено из оператора равенства и реализаций IEquatable<T>, потому что оно может привести к 1. ненужным накладным расходам в некоторых случаях и / или 2. непоследовательной производительности в зависимости от того, как часто экземпляр сравнивается сам с собой по сравнению с другими экземплярами. .

Альтернатива, которую мне не нравится, но я должен упомянуть, - это отменить эту настройку, централизовав код равенства для конкретного типа в операторе равенства и от этого зависят методы Equals. Затем можно было бы использовать ярлык ReferenceEquals(obj1,obj2) для одновременной проверки ссылочного равенства и нулевого равенства, как Филип упоминал в более ранней публикации, но эта идея вводит в заблуждение. Кажется, что вы убиваете двух зайцев одним выстрелом, но на самом деле вы создаете больше работы - после определения, что объекты не являются ни нулевыми, ни одним и тем же экземпляром, вам, кроме того, ВСЕГДА придется проверять, каждый ли экземпляр нулевой. В моей реализации вы проверяете, является ли любой отдельный экземпляр нулевым ровно один раз. К моменту вызова метода экземпляра Equals уже исключено, что первый сравниваемый объект имеет значение NULL, поэтому все, что остается сделать, это проверить, является ли другой равным NULL. Таким образом, после максимум двух сравнений мы переходим непосредственно к проверке полей, независимо от того, какой метод мы используем (Equals(object),Equals(T),==,!=). Кроме того, как я уже упоминал, если вы действительно сравниваете и возражаете против себя большую часть времени, вы можете добавить эту проверку в метод Equals непосредственно перед тем, как погрузиться в сравнение полей. Смысл добавления последнего в том, что вы все еще можете поддерживать иерархию потоков / зависимостей, не вводя избыточную / бесполезную проверку на каждом уровне.

bool comp;
if (object.IsNullOrEmpty(r1))
{
    comp = false;
}

if (object.IsNullOrEmpty(r2))
{
    comp = false;
}
return comp;

// это может помочь вам или помочь любому, кто в этом нуждается

fernando 23.11.2012 00:05

Другие вопросы по теме