【问题标题】:C# object is not null but (myObject != null) still return falseC# 对象不为空,但 (myObject != null) 仍然返回 false
【发布时间】:2010-09-14 09:40:44
【问题描述】:

我需要在对象和 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);
    }

【问题讨论】:

    标签: c# null compare


    【解决方案1】:

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

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

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

    【讨论】:

    • 我刚刚意识到我的 == 和 != 重载了!
    • 我认为有人在 != 部分中犯了错误,我会检查一下!谢谢提示。
    • 正确,重载是错误的——如果你复制下面我帖子中的代码或解释,我会删除我的帖子
    • @Philip Rieck - 完成,但我不确定你是否需要删除你的帖子(我希望我没有搞砸代码逻辑)。
    【解决方案2】:

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

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

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

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

    【讨论】:

    • 好的,我会在几分钟内完成修改。
    【解决方案3】:

    两个重载都不正确

     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,则第一个测试 (object.ReferenceEquals(r1, null)) 将返回 false,即使 r2 也为 null。

    试试

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

    【讨论】:

    • 这工作!!!!!!!!!谢谢你本来是我的“接受的答案”,但其他人先找到原因,然后你就知道了:)
    【解决方案4】:

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

    【讨论】:

    • 谢谢,但真正的原因是 == 和 != 没有很好地重载。但你的答案可能是正确的。
    【解决方案5】:

    对于类型“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&lt;T&gt; 接口方法Equals(T other)。 如果您要与另一种类型 (T2) 进行比较,请同时实现 IEquatable&lt;T2&gt;,并将该类型的字段比较代码放在 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&lt;T&gt; 实现的末尾。 ==!= 运算符具有并行但相反的实现。我更喜欢这个而不是一个引用另一个,这样就有一个额外的方法调用依赖的一个。如果!= 运算符只是简单地调用== 运算符,而不是提供同等性能的运算符,那么您不妨只使用!(obj1 == obj2) 并避免额外的方法调用。 自我比较从等于运算符和IEquatable&lt;T&gt; 实现中省略,因为它可能会引入 1. 在某些情况下不必要的开销,和/或 2. 不一致的性能取决于实例与自身比较的频率与其他实例。

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

    【讨论】:

      【解决方案6】:

      难道这里的这些检查都不对:

      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 都是非空但引用同一个对象的情况。)
      【解决方案7】:

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

      【讨论】:

        【解决方案8】:
        bool comp;
        if (object.IsNullOrEmpty(r1))
        {
            comp = false;
        }
        
        if (object.IsNullOrEmpty(r2))
        {
            comp = false;
        }
        return comp;
        

        【讨论】:

        • //它可以帮助你,或者帮助任何需要它的人
        猜你喜欢
        • 1970-01-01
        • 2011-05-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多