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

时间:2020-03-06 14:57:10  来源:igfitidea点击:

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

这是代码:

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

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

更新

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

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

解决方案

当我们有多个线程处理同一数据时,有时可能会发生这种情况。在这种情况下,我们可以使用锁来防止它们彼此混乱。

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

现在,我们已经发布了重载代码:

重载可能看起来像以下内容(代码摘自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);
}

那些运算符的重载被打破了。

首先,如果仅通过调用==并将结果取反来实现!=,它将使工作变得更加轻松。

其次,在==中进行无效检查之前,应该有:

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

所以这里的检查不正确吗?

public static bool operator !=(Region r1, Region r2)
{
    if (object.ReferenceEquals(r1, null))
    {
        return false;
    }
    if (object.ReferenceEquals(r2, null))
    {
        return 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);
    }

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

尝试

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

我们还可能需要单击正在观看的参数旁边的刷新图标。 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其他)中。

所有重载的方法和运算符都应将相等性比较任务转发给主要的类型安全的Equals(Tother)实例方法,以便保持清晰的依赖关系层次结构,并在每个级别引入更严格的保证,以消除冗余和不必要的复杂性。

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方法依赖于此。然后,可以像Philip在先前的文章中提到的那样,使用ReferenceEquals(obj1,obj2)的快捷方式同时检查引用相等和null相等,但是这种想法具有误导性。似乎我们要用一块石头杀死两只鸟,但是我们实际上要做更多的工作-在确定对象既不是null也不是同一实例之后,此外,我们还必须继续检查每个实例是否为空值。在我的实现中,我们只检查一次单个实例为null的情况。到调用Equals实例方法时,已经排除了要比较的第一个对象为空,因此剩下要做的就是检查另一个对象是否为空。因此,在最多两次比较之后,无论我们使用哪种方法(Equals(object),Equals(T),==,!=),我们都直接跳入现场检查。另外,正如我所提到的,如果我们实际上大部分时间都在进行比较并反对自己,那么我们可以在进入现场比较之前在Equals方法中添加该检查。最后添加它的要点是,我们仍然可以维护流/依赖关系层次结构,而无需在每个级别引入冗余/无用的检查。