使用 IEquatable的同级类的 C# 字典唯一性

发布于 2024-08-29 13:04:39 字数 304 浏览 11 评论 0原文

我想将两个类的实例存储在字典结构中,并使用 IEquatable 来确定这些实例的唯一性。这两个类共享一个(抽象)基类。考虑以下类:

abstract class Foo
{
   ...
}

class SubFoo1 : Foo
{
   ...
}

class SubFoo2 : Foo
{
   ...
}

字典将被声明: Dictionary

哪些类应声明为 IEquatable?这些声明的泛型类型 T 应该是什么?这可能吗?

I would like to store insances of two classes in a dictionary structure and use IEquatable to determine uniqueness of these instances. Both of these classes share an (abstract) base class. Consider the following classes:

abstract class Foo
{
   ...
}

class SubFoo1 : Foo
{
   ...
}

class SubFoo2 : Foo
{
   ...
}

The dictionary will be delcared: Dictionary<Foo, Bar>

Which classes should be declared as IEquatable? And what should the generic type T be for those declarations? Is this even possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

要走就滚别墨迹 2024-09-05 13:04:39

不要将任何内容声明为 IEquatable。正如马克所说,当涉及到继承和平等时,这通常是一个问题。

相反,计算出您想要此特定字典中的键的相等性,并实现 IEqualityComparer,然后将其传递到字典构造函数中。

通常如何比较特定情况下的键是相当清楚的。

Don't declare anything as IEquatable<T>. It's generally a problem when it comes to inheritance and equality, as Marc says.

Instead, work out what kind of equality you want for the keys in this particular dictionary, and implement IEqualityComparer<Foo>, then pass that into the dictionary constructor.

Usually it's reasonably clear how to compare keys for a specific situation.

迷乱花海 2024-09-05 13:04:39

这取决于你的课程代表什么。因此,没有“通用”解决方案。如果存在,那么 System.Object 将实现 IEquatable,因为无论如何,所有内容都已经继承自 object。因此,您可能会问关于 Object 而不是 Foo 的相同问题。

长话短说,这取决于您想要通过类层次结构实现什么目标。

长话短说,我同意无论如何都很难确定是什么使对象相等,因为即使对于相同的对象类型,也可能有不同的要求。当您使用缓存时,相等性将由对象的实体 ID 确定。当您使用执行/撤消列表时,您需要另一个限定符,因为列表中每个对象的 ID 可能都是相同的。

我想我有点离题了,但我希望我能给你一些有用的观点。 ;-)

It depends on what you classes stand for. So there is no 'generic' solution to that. If there was, then System.Object would implement IEquatable<object>, as everything inherits from object already anyway. So you could have asked the same question about Object instead of Foo.

Long story short, it depends on what you want to achieve with your class hierarchy.

Short story long, I agree it is difficult to determine what makes objects equal anyway, because even for the same object type, there might be different requirements. When you use a Cache, equality would be determined by an Entity ID of the object. When you use a Do-/Undo-List, you'd need another qualifier because the ID will probably be the same for each object in the list.

Guess I digressed a bit, but I hope I could give you some helpful points. ;-)

寄居者 2024-09-05 13:04:39

您始终可以在字典构造函数中指定自己的相等比较器。如果您不这样做,字典将查找 IEquatable,因此在您的情况下为 IEquatable 因此您应该实现该实现。

You can always specify your own equality comparer in the dictionary constructor. If you don't, the dictionary will look for IEquatable<TKey> so in your case for IEquatable<Foo> therefore you should implement that one.

御守 2024-09-05 13:04:39

当您开始获得继承时,选择 T 确实变得很棘手。基本类型是显而易见的选择,但我想知道仅重写 EqualsGetHashCode 是否更合适。

您还可能得出结论,这种复杂的场景可能不是密钥的糟糕选择,因此应使用更简单、更可预测的密钥。特别是,您希望“散列”基于类型的某些不可变方面,并且“散列”和“等于”必须兼容。如果类型没有密封,这些细微差别很难保证。

When you start getting inheritance, it indeed gets tricky to choose a T. The base-type is the obvious choice, but I wonder if it isn't more appropriate to just override Equals and GetHashCode.

You might also conclude that such complex scenarios might be poor choices for a key, and use a simpler, more predictable key instead. In particular you want the "hash" to be based on some immutable facet of the type, and the "hash" and "equals" must be compatible. These nuances are very hard to guarantee if the type isn't sealed.

因为看清所以看轻 2024-09-05 13:04:39

可继承类几乎不应该实现 IEquatable。对于任何类型 T,每个实现 IEquatable的对象都应该这样做,以便 IEquatable.Equals 的语义匹配是Object.Equals的。如果一个类为某些 Foo 实现了 IEquatable,并且派生类更改了 Object.Equals 的语义,但不重新实现 < code>IEquatable.Equals,后者的语义与前者匹配的唯一方法是接口实现简单地调用虚拟 Object.Equals 本身;如果接口只是将其参数传递给Object.Equals,那么实现它没有任何好处。

Inheritable classes should almost never implement IEquatable<T>. For any type T, every object which implements IEquatable<T> should do so such that the semantics of IEquatable<T>.Equals will match that of Object.Equals. If a class implements IEquatable<Foo> for some Foo and a derived class changes the semantics of Object.Equals but does not re-implement IEquatable<Foo>.Equals, the only way the semantics of the latter will match the former will be if the interface implementation simply calls the virtual Object.Equals itself; if the interface is simply going to pass its argument to Object.Equals, there is no benefit to implementing it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文