如何在 [重复] 的类中实现 IEquatable<MyType>
Posted
技术标签:
【中文标题】如何在 [重复] 的类中实现 IEquatable<MyType>【英文标题】:How to Implement IEquatable<MyType> in a class that [duplicate] 【发布时间】:2022-01-08 08:51:13 【问题描述】:我需要有一个 DispenseFile 类的实例,该类继承自实现 IDispenseEntity 的 DispenseEntity 使用自定义相等性来比较 List 中的元素。
我的界面是:
public interface IDispenseEntity : IEquatable<IDispenseEntity>
byte[] Id get; set;
List<byte[]> Key get;
List<byte[]> ParentKey get; set;
double Volume get; set;
public bool DispenseEnabled get; set;
string Name get; set;
我的 DispenseEntity 类:
public class DispenseEntity : IDispenseEntity, IEquatable<IDispenseEntity>
//Other properties and methods
//I've tried - this implements IEquatable:
public bool Equals(IDispenseEntity other)
return Id.SequenceEqual(other.Id);
//I've tried - this overrides default:
public override bool Equals(object obj)
return Id.SequenceEqual((obj as IDispenseEntity).Id);
我的 DispenseFile 类:
public class DispenseFile : DispenseEntity, IParent, IOutputable, IDispenseFile
//Other methods and properties
public override bool Equals(object obj)
return base.Equals(obj);
无论我在 DispenseEntity 类中为 Equals() 方法使用什么,当我尝试时它都不会被使用:
List<IDispenseEntity> before = _aList;
List<IDispenseEntity> after = _bList;
var intersect = before.Intersect(after).ToList();
相交列表有零个元素。
我非常肯定 _aList 和 _bList 都有一个 DispenseFile 实例,它继承了实现 IDispenseEntity 的 DispenseEntity。我编写了测试代码,可以在 _aList 中找到唯一的 DispenseFile 实体,并在 _bList 中找到 DispenseFile 的单个实例。这两个实例都是单独创建的,并且具有相同的属性 Id (new byte[] 1,2,3,4
)
我尝试过覆盖 Equals。我已经尝试将 IEquatable 添加到基类并实现 equals 和 GetHashCode 并且没有使用。
问题一定是我自己,我做错了什么?
【问题讨论】:
GetHashCode 绝对会 被使用,如果你覆盖 Equals,你应该肯定覆盖它。请提供minimal reproducible example,它会更容易为您提供帮助。 Intersect 在内部使用 HashSet;您必须覆盖 GetHashCode,因为它用于首先判断列表 A 中的集合是否包含列表 B 中的项目。如果您坚持使用默认的 GetHashcode,您将永远不会成功地与不同的实例相交 另请注意,实现IEquatable<ISomeInterface>
的类很奇怪。您通常应该为同一类型实现IEquatable
(即DispenseEntity
应该实现IEquatable<DispenseEntity>
)
【参考方案1】:
你甚至不需要实现 IEquatable 任何东西;覆盖 GetHashCode 和 Equals 就足够了
public class DispenseEntity : IDispenseEntity
...
public override int GetHashCode()
return new BigInteger(Id).GetHashCode(); //or your choice
public override bool Equals(object obj)
return obj is DispenseEntity x && x.Id.SequenceEqual(Id);
无论我在 DispenseEntity 类中为 Equals() 方法使用什么,它都不会被使用
确实可能不会;相交简介:
Intersect 使用 HashSet;将列表 B 的内容添加到集合中,然后枚举 A 的内容并尝试将其添加到集合中。如果 Add 返回 false,表明该项目是已知的,则从 A 中产生项目。在操作结束时,所有来自 A 且也在 B 中的项目都已返回
现在,对于使用默认哈希码提供程序来确定它是否包含某个对象 X 的 HashSet,它首先获取 X 的哈希码并查看它知道的对象以查看是否有任何其他对象具有相同的哈希码。
如果不存在具有相同哈希的已知对象,则认为该集合不包含该对象。
如果存在具有相同哈希值的对象,则它使用 Equals 来确定碰撞对象是否真的相同。如果您依赖对象的默认哈希码实现,它本质上是项目的内存地址,因此您获得相同哈希码的唯一方法是列表 A 和列表 B 共享一个实例
长话短说,如果您不覆盖 GetHashCode,您将得到一个空集结果,因为当所有 _bList
都添加到集合中,然后枚举所有 _aList
并询问集合时“有这个吗?”答案总是“否” - 永远不需要 来判断实例是否相同,因为哈希值总是不同,而交集是
(什么都没有)
..但是如果你已经覆盖了 Equals 和 GetHashCode,你应该很高兴。您甚至可以将 GetHashCode 覆盖为 return 1
(不要;这将非常低效)并且您会看到 Equals 被使用(很多)..
【讨论】:
这似乎是一个很好的解释。对此感激不尽。我会确保我覆盖了 Equals 和 GetHashCode 并看看会发生什么。 "对于有效的比较,你不会这样做;当覆盖 Equals 时,也要执行 GetHashCode" 哇,编程天才和诗人! 哦,我不知道我是否会走那么远,但我很感激你的赞美! :)以上是关于如何在 [重复] 的类中实现 IEquatable<MyType>的主要内容,如果未能解决你的问题,请参考以下文章
如何在python中实现一个好的__hash__函数[重复]
如何在Castle.Core中实现IProxyGenerationHook的类中实现Equals和GetHashCode的覆盖方法?
如何在使用 Hibernate 映射的类中实现 toString()?