如何正确覆盖平等
本文关键字:覆盖 何正确 | 更新日期: 2023-09-27 18:31:58
我对重载运算符还是新手。我以为我做得很好,直到我遇到这个问题。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");
}
}
}
当我注释掉二进制运算符时,程序按预期运行。我的问题是如何保护我的二进制运算符免受空引用的影响,以便我可以保留它们以进行手动比较?谢谢你的时间。
到目前为止给出的两个答案都是错误的。接受的答案是错误的,因为它不小心递归。另一个答案是错误的,因为它说 null 不等于 null。
你对运算符的实现都是错误的;它们需要正确处理空输入。
你的GetHashCode实现被严重破坏了;你试图将一个十四位数字转换成一种可以接受九位数字的格式。只需在日期调用GetHashCode;没有必要经历把它变成一个字符串,然后把它变成一个数字的僵化!
编写代码的正确方法是使用 object.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();
}
其他比较运算符留作练习。
看起来您正在与之比较的Task
对象之一!=
设置为 null
。内置运算符!=
比较引用并且不会中断,但您的运算符尝试取消引用任务并中断。
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 检查。
public static bool operator !=(Task t1, Task t2)
{
if (null == t1 || null == t2) { return false;}
return (t1.dateDue != t2.dateDue);
}