【问题标题】:Operator overloading ==, !=, Equals运算符重载 ==, !=, Equals
【发布时间】:2014-10-17 04:01:31
【问题描述】:

我已经通过question

我明白了,需要实现==、!=和Equals()。

public class BOX
{
    double height, length, breadth;

    // this is first one '=='
    public static bool operator== (BOX obj1, BOX obj2)
    {
        return (obj1.length == obj2.length 
                    && obj1.breadth == obj2.breadth 
                    && obj1.height == obj2.height);
    }

    // this is second one '!='
    public static bool operator!= (BOX obj1, BOX obj2)
    {
        return !(obj1.length == obj2.length 
                    && obj1.breadth == obj2.breadth 
                    && obj1.height == obj2.height);
    }

    // this is third one 'Equals'
    public override bool Equals(BOX obj)
    {
        return (length == obj.length 
                    && breadth == obj.breadth 
                    && height == obj.height);
    }
}

我假设,我已经正确编写了代码来覆盖 ==,!=,Equals 运算符。但是,我得到如下编译错误。

'myNameSpace.BOX.Equals(myNameSpace.BOX)' is marked as an override 
but no suitable method found to override.

所以,问题是 - 如何覆盖上述运算符并摆脱此错误?

【问题讨论】:

  • 不是像public override bool Equals(object o)这样的Equals的签名吗?
  • Resharper 建议像 return !(obj1 == obj2) 一样编写 !=,这应该利用您已经为 == 重载编写的内容。

标签: c# .net compiler-errors operator-overloading


【解决方案1】:

正如 Selman22 所说,您正在覆盖默认的 object.Equals 方法,该方法接受 object obj 而不是安全的编译时类型。

为了实现这一点,让你的类型实现IEquatable<Box>:

public class Box : IEquatable<Box>
{
    double height, length, breadth;

    public static bool operator ==(Box obj1, Box obj2)
    {
        if (ReferenceEquals(obj1, obj2))
        {
            return true;
        }
        if (ReferenceEquals(obj1, null))
        {
            return false;
        }
        if (ReferenceEquals(obj2, null))
        {
            return false;
        }

        return obj1.Equals(obj2);
    }

    public static bool operator !=(Box obj1, Box obj2)
    {
        return !(obj1 == obj2);
    }

    public bool Equals(Box other)
    {
        if (ReferenceEquals(other, null))
        {
            return false;
        }
        if (ReferenceEquals(this, other))
        {
            return true;
        }

        return height.Equals(other.height) 
               && length.Equals(other.length) 
               && breadth.Equals(other.breadth);
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Box);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            int hashCode = height.GetHashCode();
            hashCode = (hashCode * 397) ^ length.GetHashCode();
            hashCode = (hashCode * 397) ^ breadth.GetHashCode();
            return hashCode;
        }
    }
}

另外需要注意的是,您正在使用相等运算符进行浮点比较,您可能会遇到精度损失。

【讨论】:

    【解决方案2】:
    public class BOX
    {
        double height, length, breadth;
    
        public static bool operator == (BOX b1, BOX b2)
        {
            if (b1 is null)
                return b2 is null;
    
            return b1.Equals(b2);
        }
    
        public static bool operator != (BOX b1, BOX b2)
        {
            return !(b1 == b2);
        }
    
        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;
    
            return obj is BOX b2? (length == b2.length && 
                                   breadth == b2.breadth && 
                                   height == b2.height): false;
    
        }
    
        public override int GetHashCode()
        {
            return (height,length,breadth).GetHashCode();
        }
    }
    

    【讨论】:

      【解决方案3】:

      事实上,这是一个“如何”的主题。所以,这里是参考实现:

          public class BOX
          {
              double height, length, breadth;
      
              public static bool operator == (BOX b1, BOX b2)
              {
                  if ((object)b1 == null)
                      return (object)b2 == null;
      
                  return b1.Equals(b2);
              }
      
              public static bool operator != (BOX b1, BOX b2)
              {
                  return !(b1 == b2);
              }
      
              public override bool Equals(object obj)
              {
                  if (obj == null || GetType() != obj.GetType())
                      return false;
      
                  var b2 = (BOX)obj;
                  return (length == b2.length && breadth == b2.breadth && height == b2.height);
              }
      
              public override int GetHashCode()
              {
                  return height.GetHashCode() ^ length.GetHashCode() ^ breadth.GetHashCode();
              }
          }
      

      参考号:https://msdn.microsoft.com/en-us/library/336aedhh(v=vs.100).aspx#Examples

      更新:在operator == 实现中转换为(object) 很重要,否则,它将重新执行运算符 == 重载,从而导致堆栈溢出。感谢@grek40。

      这个(object) 转换技巧来自微软String == 实现。 SRC:https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/string.cs#L643

      【讨论】:

      • 不要写if (null == b1),它会重新执行operator ==重载,导致stackoverflow。 b2 也一样。
      • @grek40 ,if ((object)b1==null) 会避免这个问题吗?
      • 是的,这应该可以解决问题。替代方法是使用 object.ReferenceEquals 就像其他答案一样。
      • 对于HashCode的生成,最好使用一个元组。GetHashCode():(height, length, breadth).GetHashCode()。使用 XOR 的问题是高度、长度、宽度可能只使用低位而高位未使用。理想情况下,哈希使用整数的所有 32 位。这是通过将参数移位不同的值来实现的,GetHashCode() 就是这样做的。
      【解决方案4】:

      我想你是这样声明 Equals 方法的:

      public override bool Equals(BOX obj)
      

      因为object.Equals 方法接受一个对象,所以没有方法可以用这个签名覆盖。你必须像这样覆盖它:

      public override bool Equals(object obj)
      

      如果你想要类型安全的Equals,,你可以实现IEquatable&lt;BOX&gt;。

      【讨论】:

        猜你喜欢
        • 2017-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-19
        • 1970-01-01
        • 2011-06-21
        相关资源
        最近更新 更多