【问题标题】:When overloading the equality operator, what's the best way to handle null values? [duplicate]重载相等运算符时,处理空值的最佳方法是什么? [复制]
【发布时间】:2011-06-19 13:39:04
【问题描述】:

可能重复:
How do I check for nulls in an ‘==’ operator overload without infinite recursion?

假设我有这样的类型:

public class Effect
{
    public static bool operator == ( Effect a, Effect b )
    {
        return a.Equals ( b );
    }

    public static bool operator != ( Effect a, Effect b )
    {
        return !a.Equals ( b );
    }

    public bool Equals ( Effect effect )
    {
        return this.TypeID.Equals ( effect.TypeID );
    }

    public override bool Equals ( object obj )
    {
        return this.TypeID.Equals ( ( ( Effect ) obj ).TypeID );
    }
}

处理空值最可靠、最简洁的方法是什么?

我不确定是否必须同时检查当前实例 (this) 和传递的实例 (effect/obj) 是否为空?如果当前实例 (this) 为 null,编译器还会调用 effect.Equals 还是 Object.Equals?

同样,空值检查应该在哪里进行?我假设只在 Equals 方法中,而不是在相等运算符 (==, !=)。

【问题讨论】:

  • 将两个对象的相等替换为它们的属性相等真的是个好主意吗?我可以看到使用结构,但覆盖 == 类似乎是模糊错误的滋生者。
  • @djacobson,谢谢,那里的答案看起来不错。
  • @liho1eye, @Joan:MS 有一个指导方针,对于 mutable 类型重载 ==Equals 不是一个好主意。
  • @liho1eye : string 是一个引用类型(和一个集合)。基于价值的平等适用于它。
  • @Henk Holterman,字符串也是不可变的:)

标签: c# .net operator-overloading equality


【解决方案1】:

首先,this 永远不能是 null,至少在 C# 编译器生成的代码中是这样。

其次,使用ReferenceEquals 方法检查null 引用,而不要调用== 的重载版本(或执行((object) sometypeinstance) == null)。

【讨论】:

  • 谢谢,但如果我有 Effect e = null,在这种情况下它的“this”值不会是 null 吗?
  • +1,这里唯一正确的答案,认真的!
【解决方案2】:

添加这个:

 public static bool operator == ( Effect a, Effect b )     
 {  
     return a is Effect && b is Effect && a.TypeID.Equals (b.TypeID);    
 }  
 public static bool operator != ( Effect a, Effect b )
 {         
     return !(a == b );     
 }      
 public bool Equals ( Effect effect )     
 {         
    return this == effect );     
 }      
 public override bool Equals ( object obj )     
 {   
    return obj is Effect && this == obj); 
 } 

或代替最后放置:

 public override bool Equals ( object obj )     
 {   
    if (obj == null) throw new ArgumentNullException(
         "obj", "obj is null");
    if (!(obj is effect)) throw new ArgumentException(
         "obj", "obj is not an effect");
    return obj is Effect && this == obj); 
 }

【讨论】:

  • 不过最好小心点。 == 要求您还定义 !=。这可能会导致相互递归。
  • 如果您确实使用该代码,则有必要将等效代码添加到 != 方法中。
  • 这会引入堆栈溢出,不是吗? == 调用 !=、!= 调用 == 等...
  • @Charles:克里斯是对的;这将溢出。
  • 是的,现在就修复它...尝试太快的危险...
【解决方案3】:

怎么样

public static bool operator == ( Effect a, Effect b )     
{  
    return object.Equals(a, b);
}

Object.Equals() 的默认实现会为您执行 null 检查。

如果您好奇,下面是 Object.Equals() 的工作方式(由 .NET Reflector 提供):

public static bool Equals(object objA, object objB)
{
    return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));
}

【讨论】:

  • 谢谢,当我使用空值时,我的类型抛出了空引用异常。
  • 查看您的问题的 cmets - 覆盖 == 和 != 不是轻而易举的事情 :)
  • 谢谢,我没注意你留言的第一部分。
【解决方案4】:

是的,您应该检查 null。你为什么害怕那个?

请记住,当您使用 equals 时,您可能还想看看 hashcode 方法!这两种方法是相互交织的。

【讨论】:

    【解决方案5】:

    有必要检查每个带参数的方法是否存在空值。

    public class Effect
    {
        public static bool operator == ( Effect a, Effect b )
        {
            if (a == null) && (b == null) return true;
                if (a == null) return false;
                return a.Equals ( b );
        }
    
        public static bool operator != ( Effect a, Effect b )
        {
            return !(a == b);
        }
    
        public bool Equals ( Effect effect )
        {
                if (b == null) return false;
            return this.TypeID.Equals ( effect.TypeID );
        }
    
        public override bool Equals ( object obj )
        {
                if (obj == null) return false;
            return this.TypeID.Equals ( ( ( Effect ) obj ).TypeID );
        }
    }
    

    其他需要注意的事情是 GetHashCode,如果要实现相等,则应该实现 GetHashCode,如果要在字典或比较项目的类似对象中使用该对象,则 GetHashCode 应该只在不可变属性上实现。使用哈希码。

    【讨论】:

    • 谢谢,这也不会编译,对吧? (return !a == b;)?
    • 我的错误我错过了一对括号,我一定太习惯了IDE的拐杖。我已将其更改为 !(a == b);
    • np哥们,我也太习惯IDE了:O
    • -1,这会产生无限递归并且根本不会真正起作用。见stackoverflow.com/questions/73713/…
    【解决方案6】:

    Visual Studio 有一个 sn-p,它为您提供了一个基本的 Equals() 实现。我会遵循这一点,除非你有充分的理由不这样做。

    // override object.Equals
    public override bool Equals(object obj)
    {
        //       
        // See the full list of guidelines at
        //   http://go.microsoft.com/fwlink/?LinkID=85237  
        // and also the guidance for operator== at
        //   http://go.microsoft.com/fwlink/?LinkId=85238
        //
    
        if (obj == null || GetType() != obj.GetType())
        {
            return false;
        }
    
        // TODO: write your implementation of Equals() here
        throw new NotImplementedException();
        return base.Equals(obj);
    }
    
    // override object.GetHashCode
    public override int GetHashCode()
    {
        // TODO: write your implementation of GetHashCode() here
        throw new NotImplementedException();
        return base.GetHashCode();
    }
    

    【讨论】:

    • 这没有回答问题。请更正或删除它..
    • 我相信它确实回答了这个问题。在回答“你如何处理空值”这个问题时,sn-p 回答“return false”。
    • 对不起,我的错误很苛刻,但说真的,这里的问题是在运算符重载中处理空值时,这也是问题所在。即使 OP 做了你所做的,它仍然可以在重载的 ==!= 中给出空引用异常。
    猜你喜欢
    • 2010-09-10
    • 2017-11-15
    • 2016-09-27
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    • 2015-04-04
    相关资源
    最近更新 更多