C# 对象不为 null 但 (myObject != null) 仍然返回 false

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/155458/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:00:13  来源:igfitidea点击:

C# object is not null but (myObject != null) still return false

提问by Patrick Desjardins

I need to do a comparaison between an object and NULL. When the object is not NULL I fill it with some data.

我需要在对象和 NULL 之间进行比较。当对象不是 NULL 时,我用一些数据填充它。

Here is the code :

这是代码:

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

This is working but when looping and looping sometime the region object is NOT null (I can see data inside it in debug mode). In step-by-step when debugging, it doesn't go inside the IF statement... When I do a Quick Watch with these following expression : I see the (region == null) return false, AND (region != null) return false too... why and how?

这是有效的,但是当有时循环和循环时,区域对象不为空(我可以在调试模式下看到其中的数据)。在调试时的逐步调试中,它不会进入 IF 语句......当我使用以下表达式进行快速观察时:我看到 (region == null) 返回 false, AND (region != null ) 也返回 false ......为什么以及如何?

Update

更新

Someone point out that the object was == and != overloaded:

有人指出对象是 == 和 != 重载:

    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);
    }

采纳答案by Michael Burr

Is the == and/or != operator overloaded for the region object's class?

== 和/或 != 运算符是否为区域对象的类重载?

Now that you've posted the code for the overloads:

现在您已经发布了重载的代码:

The overloads should probably look like the following (code taken from postings made by Jon Skeetand Philip Rieck):

重载应该如下所示(代码取自Jon SkeetPhilip 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);
}

回答by skb

This can sometimes happen when you have multiple threads working with the same data. If this is the case, you can use a lock to prevent them from messing with eachother.

当您有多个线程处理相同的数据时,有时会发生这种情况。如果是这种情况,您可以使用锁来防止它们相互干扰。

回答by Jon Skeet

Those operator overloads are broken.

那些运算符重载被破坏了。

Firstly, it makes life a lot easier if != is implemented by just calling == and inverting the result.

首先,如果 != 是通过调用 == 并反转结果来实现的,它会让生活变得更轻松。

Secondly, before the nullity checks in == there should be:

其次,在 == 中的空性检查之前应该有:

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

回答by dlamblin

So is it that these checks here are not right:

那么这里的这些检查是不是不对的:

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

回答by Philip Rieck

Both of the overloads are incorrect

两个重载都不正确

 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);
    }

if r1 And r2 are null, the first test (object.ReferenceEquals(r1, null)) will return false, even though r2 is also null.

如果 r1 和 r2 为空,则第一个测试(object.ReferenceEquals(r1, null))将返回 false,即使 r2 也为空。

try

尝试

//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);
    }

回答by faulty

There's another possibility that you need to click the refresh icon next to the parameter that you're watching. VS try to keep up with the performance while not evaluating every statement/parameter. Take a look to make sure, before you start making changes to places that's non relevant.

还有一种可能是您需要单击您正在查看的参数旁边的刷新图标。VS 尝试跟上性能,同时不评估每个语句/参数。在开始对不相关的地方进行更改之前,请先确认一下。

回答by Triynko

For equality comparison of a type "T", overload these methods:

对于类型“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)

Your type-specific comparison code should be done in one place: the type-safe IEquatable<T>interface method Equals(T other). If you're comparing to another type (T2), implement IEquatable<T2>as well, and put the field comparison code for that type in Equals(T2 other).

您的特定于类型的比较代码应该在一个地方完成:类型安全的IEquatable<T>接口方法Equals(T other)。如果您要与另一种类型 (T2) 进行比较,也请实施IEquatable<T2>,并将该类型的字段比较代码放入 Equals(T2 other) 中。

All overloaded methods and operators should forward the equality comparison task to the main type-safe Equals(T other) instance method, such that an clean dependency hierarchy is maintained and stricter guarantees are introduced at each level to eliminate redundancy and unessential complexity.

所有重载的方法和运算符都应该将相等比较任务转发给主要的类型安全 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
}

Discussion:

讨论:

The preceding implementation centralizes the type-specific (i.e. field equality) comparison to the end of the IEquatable<T>implementation for the type. The ==and !=operators have a parallel but opposite implementation. I prefer this over having one reference the other, such that there is an extra method call for the dependent one. If the !=operator is simply going to call the ==operator, rather than offer an equally performing operator, then you may as well just use !(obj1 == obj2)and avoid the extra method call. The comparison-to-self is left out from the equals operator and the IEquatable<T>implementations, because it can introduce 1. unnecessary overhead in some cases, and/or 2. inconsistent performance depending on how often an instance is compared to itself vs other instances.

前面的实现将特定于类型(即字段相等)的比较集中到类型的IEquatable<T>实现的末尾。的==!=运营商拥有平行但相反的实施方式。我更喜欢这个而不是一个引用另一个,这样依赖一个额外的方法调用。如果!=运算符只是要调用==运算符,而不是提供同等性能的运算符,那么您最好只使用!(obj1 == obj2)并避免额外的方法调用。与自身的比较从 equals 运算符和IEquatable<T>实现中被排除在外,因为它会引入 1. 在某些情况下不必要的开销,和/或 2. 性能不一致,具体取决于实例与自身与其他实例进行比较的频率。

An alternative I don't like, but should mention, is to reverse this setup, centralizing the type-specific equality code in the equality operator instead and have the Equals methods depend on that. One could then use the shortcut of ReferenceEquals(obj1,obj2)to check for reference equality and null equality simultaneously as Philip mentioned in an earlier post, but that idea is misleading. It seems like you're killing two birds with one stone, but your actually creating more work -- after determining the objects are neither both null nor the same instance, you will then, in addition, STILL have to on to check whether each instance is null. In my implementation, you check for any single instance being null exactly once. By the time the Equals instance method is called, it's already ruled out that the first object being compared is null, so all that's left to do is check whether the other is null. So after at most two comparisons, we jump directly into the field checking, no matter which method we use (Equals(object),Equals(T),==,!=). Also, as I mentioned, if you really are comparing and object to itself the majority of the time, then you could add that check in the Equals method just before diving into the field comparisons. The point in adding it last is that you can still maintain the flow/dependency hierarchy without introducing a redundant/useless check at every level.

我不喜欢但应该提到的另一种方法是颠倒这种设置,将特定于类型的相等代码集中在相等运算符中,并使 Equals 方法依赖于它。然后可以使用快捷方式ReferenceEquals(obj1,obj2)像 Philip 在之前的帖子中提到的那样同时检查引用相等性和 null 相等性,但这种想法具有误导性。看起来你是用一块石头杀死两只鸟,但你实际上创造了更多的工作——在确定对象既不是空的也不是同一个实例之后,你将此外,仍然必须检查每个实例是否一片空白。在我的实现中,您只检查一次是否为空的单个实例。当 Equals 实例方法被调用时,已经排除了第一个被比较的对象为空,所以剩下要做的就是检查另一个是否为空。所以最多经过两次比较后,我们直接跳转到字段检查,无论我们使用哪种方法(Equals(object),Equals(T),==,!=)。此外,正如我所提到的,如果您确实在大部分时间都在比较和反对自己,那么您可以在深入进行字段比较之前在 Equals 方法中添加该检查。最后添加它的重点是您仍然可以维护流/依赖关系层次结构,而无需在每个级别引入冗余/无用检查。

回答by fernando

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

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