当我在msdn上查找通用IEqualityComparer
接口时,我注意到接口是在一个单独的'comparer'类中实现的,而不是在类本身中实现的IEquatable<T>
。当我搜索更多的例子时,每一个都使用了一个单独的类,让我想知道:为什么不在类本身上实现它?
我可以想象覆盖object.Equals
和object.GetHashCode
不被认为是好习惯,因为它用于很多不同的情况,但即使msdn说(强调我的):
此界面允许实施集合的自定义相等比较。
因此它的用途几乎仅限于Linq。我可以想到为什么要定义一个单独的比较器类只有两个原因:
所以我的问题是:
有什么特别的原因让我忽略了导致每个人定义另一个comparerclass只是为了比较而不是仅仅在类本身上实现接口(在我看来,至少可以说这不会更糟)?
一个小例子:
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(); }
}
答案 0 :(得分:3)
IComparer<T>
以及IEqualityComparer<T>
使用两个 T实例,因此无需将其作为T
类的一部分实现;但是,在IEqualityComparer<T>
中实施T
是一种很好的做法,该方案可以
public partial class Test {
private 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();
}
}
// Please, note "static"
public static IEqualityComparer<Test> MyTestComparer {get;} = new TestComparer();
public int id { get; set; }
public DateTime date { get; set; }
...
}
在这种情况下,您只需使用您想要的比较器:
int distinctCountComparerClass = testList.Distinct(Test.MyTestComparer).Count();
答案 1 :(得分:3)
为什么不在课堂上实现呢?
因为没有意义。 IEqualityComparer<T>
的完整目的是在T
类型之外实施,因为它定位于帖子中的&#34;原因1&#34; 。
如果您希望类本身实现相等逻辑,那么您应该实现专门为此类场景提供的IEquatable<T>
,EqualityComparer<T>.Default
将随时为您的实现提供必要的桥梁{需要{1}}并且未明确指定。
由于该类只能提供一个没有任何动态行为和/或选项的硬编码逻辑,因此它被认为是默认相等逻辑,因此静态名称{{1提供访问权限的属性。
答案 2 :(得分:2)
简单地说,通过这种方式,您可以根据上下文使用不同的方法来比较同一个类中的对象。
它基本上是控制反转:不是类本身决定另一个类可能想要比较它的实例。
答案 3 :(得分:0)
实现IEqualityComparer<T>
而不是IEquatable<T>
是一个好习惯,因为当类实现IEquatable<T>
接口时,它会输入一个合同,其中规定“我知道如何比较类型为T
或从T
派生的任何类型的两个实例,以确保相等”。但是,如果派生该类,则基类不太可能知道如何进行有意义的比较。因此,该隐式合同现在被破坏了。
或者,可以将其实例设为comparable
的类可以设为sealed
,但是由于在此对话线程中已经说明了这些原因,所以另一种方法更为优雅。