【发布时间】:2016-02-10 11:51:22
【问题描述】:
当我在msdn 上查找通用IEqualityComparer 接口时,我注意到该接口是在一个单独的“比较器”类中实现的,而不是在类本身中实现的IEquatable<T>。当我搜索更多示例时,每个示例都使用一个单独的类,这让我想知道:为什么不在类本身上实现它?
我可以想象,覆盖 object.Equals 和 object.GetHashCode 并不被认为是好的做法,因为它用于许多不同的情况,但即使是 msdn 也说(强调我的):
此接口允许为集合实现自定义相等比较。
所以它的用途几乎仅限于 Linq。我能想到为什么要定义一个单独的比较器类只有两个原因:
- 类集合上的不同方法需要不同的比较器。
- 该类很大,不希望实例化它的另一个对象(尽管如果这确实是问题所在,为什么不拥有它的完整集合还不错?)。
所以我的问题是:
是否有任何我忽略的特殊原因导致每个人都定义另一个比较器类只是为了进行比较,而不是仅仅在类本身上实现接口(至少在我看来这不会更糟)?
一个小例子:
public static void Main(string[] args)
{
Test t1 = new Test { id = 1, date = default(DateTime) };
Test t2 = new Test { id = 1, date = default(DateTime) };
Test t3 = new Test { id = 0, date = default(DateTime) };
List<Test> testList = new List<Test>{ t1, t2, t3 };
//Same result
int distinctCountClass = testList.Distinct(new Test()).Count();
int distinctCountComparerClass = testList.Distinct(new TestComparer()).Count();
}
public partial class Test
{
public int id { get; set; }
public DateTime date { get; set; }
}
public partial class Test : IEqualityComparer<Test>
{
public bool Equals(Test x, Test y) { return x.id == y.id && x.date == y.date; }
public int GetHashCode(Test obj) { return obj.id.GetHashCode(); }
}
public class TestComparer : IEqualityComparer<Test>
{
public bool Equals(Test x, Test y) { return x.id == y.id && x.date == y.date; }
public int GetHashCode(Test obj) { return obj.id.GetHashCode(); }
}
【问题讨论】:
-
第一个原因你是正确的,第二个原因是部分正确的。这个类是“大”的,但它与实例化无关,而是与“你的类做的太多”有关。代表一组特定数据或行为的类与比较两个这样做的类的类有很大不同。
-
使用一个对象的实例来比较两个相同类型的其他实例似乎很不自然......如果你想为该类型中的一个类型实现一个比较运算符,你应该实现@ 987654327@
-
@MatthewWatson 是的,但是许多 linq 方法需要
IEqualityComparer<T>、Distinct、Groupby 等实例。如果我只实现IEquatable<T>这些方法将不起作用 -
如果你想使用
IEqualityComparer<T>类型T然后实现IEquatable<T>并使用EqualityComparer<T>.Default它将自动使用你为@ 编写的IEqualityComparer<T>的实现987654335@. -
有点跑题了,但我也想指出,在实现
IEqualityComparer<T>ORIEquatable<T>时,通常应该只在比较中使用不可变属性。原因是,如果它们是可变的,并且您将对象放入 HashSet 之类的集合中,然后改变其中一个属性,则可能会发生令人讨厌的事情。