C# 如何正确地覆盖平等?

C# 如何正确地覆盖平等?,c#,binary,overloading,operator-keyword,C#,Binary,Overloading,Operator Keyword,我对重载操作符还是新手。在我遇到这个问题之前,我一直认为我做得很好。在!=上引发NullReferenceException操作人员我假设它在CompareTo方法中使用它,但我不完全确定。如果有人能给我指出正确的方向,我将非常感激 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Li

我对重载操作符还是新手。在我遇到这个问题之前,我一直认为我做得很好。在!=上引发NullReferenceException操作人员我假设它在CompareTo方法中使用它,但我不完全确定。如果有人能给我指出正确的方向,我将非常感激

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");
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统图;
使用System.Linq;
使用系统文本;
使用System.Windows.Forms;
命名空间Windows窗体应用程序2
{
公共部分类Form1:Form
{
公共表格1()
{
初始化组件();
列表任务=新列表();
tasks.Add(新任务(“first”,DateTime.Now.AddHours(2));
添加(新任务(“第二个”,DateTime.Now.AddHours(4));
tasks.trimpose();
tasks.Sort();
}
}
公共类任务:IComparable
{
公共任务()
{
}
公共任务(字符串nameIn、日期时间dueIn)
{
nameOfTask=nameIn;
dateDue=dueIn;
}
DateTime dateDue;
任务的字符串名称;
公共静态布尔运算符(任务t1、任务t2)
{
返回(t1.dateDue>t2.dateDue);
}
公共静态布尔运算符==(任务t1、任务t2)
{
返回(t1.dateDue==t2.dateDue);
}
公共静态布尔运算符!=(任务t1、任务t2)
{
返回(t1.dateDue!=t2.dateDue);
}
公共覆盖int GetHashCode()
{
返回Int32.Parse(this.dateDue.ToString(“yyyymmddhhmmss”);
}
公共覆盖布尔等于(System.Object obj)
{
if(obj==null)返回false;
任务t=作为任务的obj;
if((System.Object)t==null)返回false;
返回(this.dateDue==t.dateDue);
}
int IComparable.CompareTo(对象对象)
{
if(obj==null)返回1;
任务t=作为任务的obj;
如果(t!=null)
{
返回此.dateDue.CompareTo(t.dateDue);
}
其他的
抛出新ArgumentException(“对象不是任务”);
}
}
}
当我注释掉二进制运算符时,程序按预期运行。我的问题是如何保护我的二进制运算符不受空引用的影响,以便保留它们进行手动比较?
谢谢您的时间。

它看起来像是您正在与
进行比较的
任务
对象之一=设置为
null
。内置运算符
=比较引用,不中断,但操作员尝试取消引用任务,并中断

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

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

当两个任务都为
null
时,此实现返回
false
。您应该在
==
运算符中实现对称空检查。

到目前为止给出的两个答案都是错误的。被接受的答案是错误的,因为它意外地重复出现。另一个答案是错误的,因为它说null不等于null

您对运算符的实现都是错误的它们需要正确处理空输入。

您的GetHashCode实现被严重破坏;您试图将14位数字转换为可接受9位数字的格式。只需在日期上调用GetHashCode;没有必要经历把它变成一个字符串然后把它变成一个数字的繁琐过程

编写代码的正确方法是使用
对象。ReferenceEquals
进行引用比较,而不是使用
=
=运算符;执行意外递归太容易了

典型的模式如下:

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

其他比较运算符留作练习。

您要与之进行比较的
任务
对象之一=
设置为
null
。右-o。。你需要假设
t1
和/或
t2
在所有这些静态函数中都可以为空..嗯,如果
t1
为空且
t2
不为空,你不希望它返回
true
?这就是一个例子。op应该足够聪明,可以定义自己的逻辑。在与
null
进行比较之前,您还忘记了将
t1
/
t2
转换为
对象。简单地说这是一个例子并不能说明搞乱了
null==null
这个重要的特例。最初的海报提出了这个问题,因为他们不知道如何正确地做。假设原始海报“足够聪明”能够检测并修复你的bug,这就否定了问题的前提,它不是bug。这就是一个例子。两个空值是否相等是一个不能简单假设的实现细节。由OP定义返回结果。OP正在比较属性的相等性。当一个或多个输入为空时,它们没有为我们提供足够的信息,我们任何人都无法假设正确的返回值。谢谢,我尝试了类似的方法,但只得到了堆栈溢出,我知道哪里出了问题。你能解释一下什么是对称空检查吗(谷歌似乎对此感到困惑)?@Powe8525当我提到你的
bool操作符==
的行为需要与你的
bool操作符的行为对称时=
,我的意思是它应该将两个
null
值视为相等,并且
null
不应该等于非null值。
的实现=遵循这些规则,因此
==
的实现也应该遵循这些规则。@Powe8525:您是正确的;这里给出的代码被破坏了,因为它调用自己。正确的代码是以if(object.ReferenceEquals(t1,null)){return!object.ReferenceEquals(t2,null);}