Объект C # не является нулевым, но (myObject! = Null) все еще возвращает false - PullRequest
17 голосов
/ 01 октября 2008

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

Вот код:

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

Это работает, но когда зацикливается и зацикливается иногда, объект region НЕ равен NULL (я вижу данные внутри него в режиме отладки). В пошаговом режиме при отладке он не входит в оператор IF ... Когда я выполняю Quick Watch со следующим выражением: я вижу (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);
    }

Ответы [ 8 ]

29 голосов
/ 01 октября 2008

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

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

Перегрузки должны выглядеть следующим образом (код взят из сообщений, сделанных Jon Skeet и Philip Rieck ):

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);
}
16 голосов
/ 01 октября 2008

Эти перегрузки оператора устранены.

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

Во-вторых, перед проверкой недействительности == должно быть:

if (object.ReferenceEquals(r1, r2))
{
    return true;
}
7 голосов
/ 01 октября 2008

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

 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 равны нулю, первый тест ( object.ReferenceEquals (r1, null) ) вернет false, даже если r2 также равен нулю.

1008 * попробовать *

//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);
    }
3 голосов
/ 01 октября 2008

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

2 голосов
/ 09 апреля 2009

Для сравнения на равенство типа "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) и избежать дополнительного вызова метода. Сравнение с самим собой исключено из оператора equals и реализаций IEquatable<T>, поскольку в некоторых случаях оно может привести к 1. ненужным издержкам и / или 2. несовместимой производительности в зависимости от того, как часто экземпляр сравнивается с самим собой по сравнению с другие случаи.

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

0 голосов
/ 23 ноября 2012
bool comp;
if (object.IsNullOrEmpty(r1))
{
    comp = false;
}

if (object.IsNullOrEmpty(r2))
{
    comp = false;
}
return comp;
0 голосов
/ 01 октября 2008

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

0 голосов
/ 01 октября 2008

Так что эти проверки здесь не правы:

public static bool operator !=(Region r1, Region r2)
{
    if (object.ReferenceEquals(r1, null))
    {
        return false;
    }
    if (object.ReferenceEquals(r2, null))
    {
        return false;
    }
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...