这个MSDN article说明何时将类型声明为值类型(struct)与引用类型(class)。特别是,它说:
AVOID定义结构,除非该类型具有以下所有特征:
- 它逻辑上表示单个值,类似于原始类型(int,double等)。
- 实例大小小于16个字节。
- 这是不可改变的。
- 不必频繁装箱。
在所有其他情况下,您应该将类型定义为类。
然后,this MSDN article详细说明了在类型上覆盖Object.Equals()的一些指导原则,包括:
当一个类型是不可变的时,...重载operator ==来比较值相等而不是引用相等可能是有用的,因为作为不可变对象,只要它们具有相同的值,它们就可以被认为是相同的。在非不可变类型中覆盖operator ==不是一个好主意。
所以在我看来,如果一个类型是不可变的,你只需将它声明为一个结构并覆盖ValueType.Equals()。但是,如果你的类型被声明为一个类,理论上你只需要引用语义。 This SO post似乎支持这一点。所以我的问题是,为什么你会打扰在引用类型上覆盖Equals()?这样做就像是说引用语义对于你的引用类型来说还不够好,这没有任何意义对我来说。我能想到的唯一例子是,如果你有一个包含可变字段和不可变字段的大型(> 16字节实例)类,但即便如此,似乎只需要引用语义就可以了。
答案 0 :(得分:1)
对于您的具体问题 - “为什么您会在引用类型上打扰覆盖Equals()?”:如果您希望通过其他.NET方法将该类的两个实例视为相等,则会覆盖Equals()如果他们不是同一个实例。
考虑List<T>.Contains()
。通过重写Equals()
,即使被比较的特定类实例实际上不是同一个实例,也可以确保该方法为您提供正确的结果。
我自己在WPF中经常遇到这个问题。我有一种情况,某些控件(特别是ListBox
)有我的对象的副本,这些副本与我测试它们的实例不同。这使得像ScrollIntoView
和SelectedItem
属性这样的方法在我在类上覆盖Equals
之前无法正常工作。我可以想到一个特定的例子,肯定会发生这种情况:假设你有一个Person
类,其中包含由于数据库查询而创建的实例列表。您使用该结果集填充ListBox
。然后,您将从不同的数据库查询(可能是某种过滤器)中获得新的结果集,现在要选择ListBox
中第二个查询结果中的所有项目。如果您没有覆盖Equals
,那么您将无法设置SelectedItems
,因为ListBox
中的实例与第二个中的实例不同查询。正如评论中指出的那样,还有其他方法,但在我看来,覆盖Equals
提供了最清晰的解决方案。
这只是一个例子。我相信你不久就会遇到别人。