简体   繁体   English

如何正确地覆盖平等?

[英]How to properly override equality?

I am still new to overloading operators. 我仍然是超载运营商的新手。 I thought i was doing a great job until i hit this problem. 在我遇到这个问题之前,我以为自己做得很好。 NullReferenceException is thrown on the != operator. 在!=运算符上抛出NullReferenceException。 I assume its using it in the CompareTo method but i'm not totally sure. 我假设它在CompareTo方法中使用它,但我不完全确定。 If anyone can point me in the right direction i would be very grateful. 如果有人能指出我正确的方向,我将非常感激。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            List<Task> tasks = new List<Task>();
            tasks.Add(new Task( "first",  DateTime.Now.AddHours(2)));
            tasks.Add(new Task( "second", DateTime.Now.AddHours(4)));
            tasks.TrimExcess();
            tasks.Sort();
        }
    }
    public class Task : IComparable
    {
        public Task()
        {
        }
        public Task(string nameIn, DateTime dueIn)
        {
            nameOfTask = nameIn;
            dateDue = dueIn;
        }
        DateTime dateDue;
        string nameOfTask;

        public static bool operator <(Task t1, Task t2)
        {
            return (t1.dateDue < t2.dateDue);
        }
        public static bool operator >(Task t1, Task t2)
        {
            return (t1.dateDue > t2.dateDue);
        }
        public static bool operator ==(Task t1, Task t2)
        {
            return (t1.dateDue == t2.dateDue);
        }
        public static bool operator !=(Task t1, Task t2)
        {
                return (t1.dateDue != t2.dateDue);

        }
        public override int GetHashCode()
        {
            return Int32.Parse(this.dateDue.ToString("yyyymmddhhmmss"));
        }
        public override bool Equals(System.Object obj)
        {
            if (obj == null) return false;    

            Task t = obj as Task;
            if ((System.Object)t == null) return false;
            return (this.dateDue == t.dateDue);
        }
        int IComparable.CompareTo(object obj)
        {
            if (obj == null) return 1;

            Task t = obj as Task;
            if (t != null)
            {
                return this.dateDue.CompareTo(t.dateDue);
            }
            else
                throw new ArgumentException("Object is not a Task");
        }
    }
}

When i comment out the binaory operators the program functions as intended. 当我注释掉binaory操作符时,程序按预期运行。 My question is how can i protect my binary operators from null references so i can keep them for manual comparisons? 我的问题是如何保护我的二元运算符免受空引用的影响,以便我可以将它们保存为手动比较? Thank you for your time. 感谢您的时间。

Both the answers given so far are wrong. 到目前为止给出的答案都是错误的。 The accepted answer is wrong because it accidentally recurses. 接受的答案是错误的,因为它不小心递归。 The other answer is wrong because it says that null is not equal to null. 另一个答案是错误的,因为它表示null不等于null。

Your implementations of the operators are all wrong; 你的运算符实现都是错的; they are required to correctly handle null inputs. 他们需要正确处理空输入。

Your implementation of GetHashCode is deeply broken; 你的GetHashCode实现已经彻底破坏了; you attempt to put a fourteen digit number into a format that can accept nine digits. 您尝试将十四位数字放入可接受九位数的格式中。 Simply call GetHashCode on the date; 只需在日期调用GetHashCode; there is no need to go through this rigamarole of turning it into a string and then turning that into a number! 没有必要经历这种把它变成一个字符串然后把它变成一个数字的蠢事!

The right way to write the code is to use object.ReferenceEquals to do reference comparisons rather than using the == and != operators; 编写代码的正确方法是使用object.ReferenceEquals进行引用比较,而不是使用==!=运算符; it is far too easy to do an accidental recursion. 进行意外递归太容易了。

The typical pattern goes like this: 典型的模式是这样的:

public static bool operator ==(Task t1, Task t2)         
{
    if (object.ReferenceEquals(t1, t2)) return true;
    // All right. We know that they are (1) not the same object, and
    // (2) not both null. Maybe one of them is null.
    if (object.ReferenceEquals(t1, null)) return false;
    if (object.ReferenceEquals(t2, null)) return false;
    // They are not the same object and both are not null.
    return t1.dateDue == t2.dateDue;
}

public static bool operator !=(Task t1, Task t2)         
{
    // Simply call the == operator and invert it.
    return !(t1 == t2);
}

public override bool Equals(object t)
{
    return (t as Task) == this;   
}

public override int GetHashCode()
{
    return this.dateDue.GetHashCode();
}

The other comparison operators are left as an exercise. 其他比较运算符留作练习。

It looks like one of the Task objects that you are comparing with != is set to null . 它看起来像您要比较的Task对象之一!=设置为null The built-in operator != compares the references and does not break, but your operator tries to dereference the task, and breaks. 内置运算符!=比较引用并且不会中断,但运算符会尝试取消引用任务,并中断。

public static bool operator !=(Task t1, Task t2) {
    if (ReferenceEquals(t1, null)) {
        return !ReferenceEquals(t2, null); // return true only if t2 is *not* null
    }
    if (ReferenceEquals(t2, null)) {
        return true; // we know that t1 is not null
    }
    return (t1.dateDue != t2.dateDue);
}

This implementation returns false when both tasks are null . 当两个任务都为null时,此实现返回false You should implement a symmetric null checking in the == operator. 您应该在==运算符中实现对称空值检查。

 public static bool operator !=(Task t1, Task t2) 
        { 
              if (null == t1 || null == t2) { return false;}
                return (t1.dateDue != t2.dateDue); 

        } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM