【问题标题】:In C#, how do I overload the Equals operator in my class properly so that Queue.Contains() works?在 C# 中,如何正确重载类中的 Equals 运算符以便 Queue.Contains() 工作?
【发布时间】:2012-10-10 05:23:50
【问题描述】:

我创建了一个类 State。对于 State 对象的 Queue,我想测试 Queue 是否已经包含相等值的 State 对象。两个 State 对象,每个都包含一个 2D 布尔数组,当数组的所有值相等且顺序相同时,它们相等。

这是我的相关代码:

public class State {
   Boolean[,] grid = new Boolean[4,4];

   Public State(Boolean[,] passedGrid){ //Constructor
       grid = Array.Copy(passedGrid, grid, 16);
   }

   public bool Equals(State s2){ //Overloaded equals operator
         for (int x = 0; x < 4; x++){
                 for (int y = 0; y < 4; y++){
                      if (grid[x, y] != s2.grid[x, y]){
                            return false;
                        }
                    }
                }
                return true;
            }

}

    public void testContains(Boolean[] testArray) {
        Queue<State> testQueue = new Queue<State>();
        State s1 = new State(testArray);
        State s2 = new State(testArray);
        testQueue.Enqueue(s1);
        Boolean b = testQueue.Contains(s2);
    }

不幸的是,当调用 testContains() 并且我在最后检查 testQueue.Contains(s2) 的值时,它仍然说测试是错误的,即使它们具有相同的数组值并且 Equals 运算符被重载以进行测试为了那个原因。我必须做什么或改变才能让 Queue.Contains 与我的对象一起工作?我在某处读到,建议在 Equals 重载时重载 getHashCode() 。在这种情况下我需要这样做吗?如果是这样,重载的getHashCode()应该做什么?

【问题讨论】:

  • 您的 Equals 方法没有覆盖基类实现,而是创建了一个新方法。尝试将 override 关键字添加到 Equals 方法中,然后查看它是否有效。

标签: c# containers overloading equals


【解决方案1】:

要覆盖 Equals,您需要使用 object 作为参数类型和关键字 override

所以你可以尝试类似的东西

    public override bool Equals(object obj)
    {
        return Equals(obj as State);
    }
    public bool Equals(State s2)
    { //Overloaded equals operator 
        for (int x = 0; x < 4; x++)
        {
            for (int y = 0; y < 4; y++)
            {
                if (grid[x, y] != s2.grid[x, y])
                {
                    return false;
                }
            }
        }
        return true;
    }

您可能还应该包括对null 的测试

看看Guidelines for Overloading Equals() and Operator == (C# Programming Guide)

【讨论】:

  • obj as State 可能返回 null。
  • @SeanU,将其添加到 OP 应检查的分析器中。
【解决方案2】:

你应该override等于

public override bool Equals(object s2)
{
    //implementation
}

为了更好的实践,您应该实现一些其他接口,例如:IEquatableIEqualtable&lt;State&gt; 和方法GetHashCode。覆盖Equals方法和IEquatableIEqualtable&lt;T&gt;中的Equals方法可以共享一个公共的私有Equals方法。

【讨论】:

    【解决方案3】:

    您缺少覆盖关键字

       public override bool Equals(Object obj) {
           // fill in the body
        }
    

    【讨论】:

    • 当我这样做时,我收到错误“找不到合适的方法来覆盖”
    • 这不可能发生,因为默认情况下所有类都继承对象类无论如何尝试显式继承对象类。
    • 还要确保准确复制我的代码并填写正文。
    【解决方案4】:

    你只需要覆盖类Object上定义的虚方法:

    public override Equals(object other)
    {
       if(other is State)
            return Equals((State)other); 
       return base.Equals(other);
    }
    

    你需要使用这个泛型重载,因为这个方法被Contains方法使用,仅仅添加同名的实例方法是不够的。

    【讨论】:

      【解决方案5】:

      请在下面找到适合您的代码:

          public class State : Object {
         Boolean[,] grid = new Boolean[4,4];
      
         public State(Boolean[,] passedGrid){ //Constructor
             Array.Copy(passedGrid, grid, 16);
         }
      
         public override bool Equals(Object s2){ //Overloaded equals operator
               for (int x = 0; x < 4; x++){
                       for (int y = 0; y < 4; y++){
                            if (grid[x, y] != ((State)s2).grid[x, y]){
                                  return false;
                              }
                          }
                      }
                      return true;
                  }
      
      }
      
      
          class Program
          {
              Boolean[,] testArray = new Boolean[4, 4];
      
              public static void Main()
              {
                  Program p = new Program();
                  p.testContains(p.testArray);
              }
      
              public void testContains(Boolean[,] testArray)
              {
                  Queue<State> testQueue = new Queue<State>();
                  State s1 = new State(testArray);
                  State s2 = new State(testArray);
                  testQueue.Enqueue(s1);
                  Boolean b = testQueue.Contains(s2);
                  //b is true here
              }
      
          }
      }
      

      另外,请查看以下链接以获取覆盖 Equals 方法的指南:

      http://msdn.microsoft.com/en-us/library/ms173147(v=vs.80).aspx

      【讨论】:

      • 覆盖Equals(Object)的代码也应该覆盖GetHashCode()
      【解决方案6】:

      对于定义自定义相等关系的类类型,应适用以下内容:

      1. 类应该是不可变的,并且不能封装可变状态。当且仅当此类引用仅用于封装此类对象的 *identities* 或其不可变属性时,不可变类保存对可变对象的引用是可以接受的。
      2. 类必须重写 `bool Equals(Object Other)` 以便在 `Other` 是类的等价实例时返回 `true`(实例等价于自身;对于可变类型,实例是 * only* 等同于自身的东西)。
      3. 该类必须重写“int GetHashCode()”,这样任何两个等效实例都将返回相同的值,并且最好使两个任意选择的非等效实例不太可能返回相同的值。
      4. 如果类是密封的,除了执行上述操作外,它还可以为自己的类型实现`IEquatable`。未密封的类不应实现 `IEquatable`。

      关于您的特定类,我建议由于只有 65,536 个可能的不同实例,您应该简单地存储一个 Integer,它标识使用了哪种位组合,在 Equals 中进行比较,然后返回它对于GetHashCode

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-17
        • 2022-01-20
        • 1970-01-01
        • 1970-01-01
        • 2012-05-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多