我想将两个类的实例存储在字典结构中,并使用 IEquatable 来确定这些实例的唯一性。这两个类共享一个(抽象)基类。考虑以下类:
abstract class Foo
{
...
}
class SubFoo1 : Foo
{
...
}
class SubFoo2 : Foo
{
...
}
字典将被删除:Dictionary<Foo, Bar>
哪些类应该声明为 IEquatable?那些声明的泛型类型 T 应该是什么?这甚至可能吗?
我想将两个类的实例存储在字典结构中,并使用 IEquatable 来确定这些实例的唯一性。这两个类共享一个(抽象)基类。考虑以下类:
abstract class Foo
{
...
}
class SubFoo1 : Foo
{
...
}
class SubFoo2 : Foo
{
...
}
字典将被删除:Dictionary<Foo, Bar>
哪些类应该声明为 IEquatable?那些声明的泛型类型 T 应该是什么?这甚至可能吗?
不要将任何东西声明为IEquatable<T>
. 正如 Marc 所说,在继承和平等方面,这通常是一个问题。
相反,为这个特定字典中的键计算出你想要什么样的相等性,并实现IEqualityComparer<Foo>
,然后将其传递给字典构造函数。
通常,如何比较特定情况下的密钥是相当清楚的。
这取决于你的课程代表什么。因此,没有“通用”解决方案。如果有,那么System.Object
将实现,因为无论如何IEquatable<object>
都继承自。object
所以你可以问同样的问题,Object
而不是Foo
.
长话短说,这取决于你想用你的类层次结构实现什么。
长话短说,我同意很难确定什么使对象相等,因为即使对于相同的对象类型,也可能有不同的要求。当您使用缓存时,相等性将由对象的实体 ID 确定。当您使用 Do-/Undo-List 时,您需要另一个限定符,因为列表中每个对象的 ID 可能相同。
我想我离题了一点,但我希望我能给你一些有用的观点。;-)
当您开始获得继承时,选择T
. 基本类型是显而易见的选择,但我想知道是否只覆盖Equals
and是否更合适GetHashCode
。
您可能还得出结论,这样复杂的场景可能不是键的错误选择,而是使用更简单、更可预测的键。特别是您希望“哈希”基于类型的某些不可变方面,并且“哈希”和“等于”必须兼容。如果类型不是,这些细微差别很难保证sealed
。
您始终可以在字典构造函数中指定自己的相等比较器。如果你不这样做,字典会IEquatable<TKey>
在你的情况下寻找,IEquatable<Foo>
因此你应该实现那个。
可继承的类几乎不应该实现IEquatable<T>
。对于任何类型T
,实现的每个对象都IEquatable<T>
应该这样做,以使 的语义与 的语义相IEquatable<T>.Equals
匹配Object.Equals
。如果一个类实现IEquatable<Foo>
了一些Foo
并且派生类改变了语义Object.Equals
但没有重新实现IEquatable<Foo>.Equals
,那么后者的语义匹配前者的唯一方法是接口实现简单地调用虚拟Object.Equals
本身;如果接口只是将其参数传递给Object.Equals
,则实现它没有任何好处。