使用IEqualityComparer和Equals / GethashCode Override有什么区别?

当我使用字典有时我必须更改默认的等于意思,以便比较键。 我看到如果我覆盖键的类上的Equals和GetHashCode,或者我创建了一个实现IEqualityComparer的新类,我有相同的结果。 那么使用IEqualityComparer和Equals / GethashCode Override有什么区别? 两个例子:

class Customer { public string name; public int age; public Customer(string n, int a) { this.age = a; this.name = n; } public override bool Equals(object obj) { Customer c = (Customer)obj; return this.name == c.name && this.age == c.age; } public override int GetHashCode() { return (this.name + ";" + this.age).GetHashCode(); } } class Program { static void Main(string[] args) { Customer c1 = new Customer("MArk", 21); Customer c2 = new Customer("MArk", 21); Dictionary d = new Dictionary(); Console.WriteLine(c1.Equals(c2)); try { d.Add(c1, "Joe"); d.Add(c2, "hil"); foreach (KeyValuePair k in d) { Console.WriteLine(k.Key.name + " ; " + k.Value); } } catch (ArgumentException) { Console.WriteLine("Chiave già inserita in precedenza"); } finally { Console.ReadLine(); } } } 

}

第二个 :

 class Customer { public string name; public int age; public Customer(string n, int a) { this.age = a; this.name = n; } } class DicEqualityComparer : EqualityComparer { public override bool Equals(Customer x, Customer y) // equals dell'equalitycomparer { return x.name == y.name && x.age == y.age; } public override int GetHashCode(Customer obj) { return (obj.name + ";" + obj.age).GetHashCode(); } } class Program { static void Main(string[] args) { Customer c1 = new Customer("MArk", 21); Customer c2 = new Customer("MArk", 21); DicEqualityComparer dic = new DicEqualityComparer(); Dictionary d = new Dictionary(dic); Console.WriteLine(c1.Equals(c2)); try { d.Add(c1, "Joe"); d.Add(c2, "hil"); foreach (KeyValuePair k in d) { Console.WriteLine(k.Key.name + " ; " + k.Value); } } catch (ArgumentException) { Console.WriteLine("Chiave già inserita in precedenza"); } finally { Console.ReadLine(); } } } 

}

两个例子都有相同的结果。

提前致谢。

当您重写EqualsGetHashCode您正在更改对象确定它是否等于另一个的方式。 还有一个注意事项,如果使用==运算符比较对象,它将不会具有与Equals相同的行为,除非您也覆盖运算符。

这样做就改变了单个类的行为,如果你需要为其他类提供相同的逻辑呢? 如果您需要“通用比较”。 这就是为什么你有IEqualityComparer

看看这个例子:

 interface ICustom { int Key { get; set; } } class Custom : ICustom { public int Key { get; set; } public int Value { get; set; } } class Another : ICustom { public int Key { get; set; } } class DicEqualityComparer : IEqualityComparer { public bool Equals(ICustom x, ICustom y) { return x.Key == y.Key; } public int GetHashCode(ICustom obj) { return obj.Key; } } 

我有两个不同的类,都可以使用相同的比较器。

 var a = new Custom { Key = 1, Value = 2 }; var b = new Custom { Key = 1, Value = 2 }; var c = new Custom { Key = 2, Value = 2 }; var another = new Another { Key = 2 }; var d = new Dictionary(new DicEqualityComparer()); d.Add(a, "X"); // d.Add(b, "X"); // same key exception d.Add(c, "X"); // d.Add(another, "X"); // same key exception 

请注意,我没有必须在两个类中都不重写EqualsGetHashCode 。 我可以在任何实现ICustom对象中使用这个比较器而不必重写比较逻辑。 我还可以为“父类”创建IEqualityComparer ,并在inheritance的类上使用。 我可以让比较器以不同的方式运行,我可以让一个比较Value而不是Key

因此, IEqualityComparer可以提供更大的灵活性,您可以实现通用解决方案。

对象的Equals() GetHashCode()实现对象固有的相等概念。 但是,您可能希望使用等同的替代概念 – 例如,仅使用ZIP代码而不是完整地址的地址对象的相等比较器。

对于这个目的,它基本上是相同的,只有一个微妙的区别。 在第一个示例中,您使用Object类型的参数覆盖Equals,然后必须将其强制转换为Customer,但是,在第二个示例中,您可以使用Customer类型的参数,这意味着无需强制转换。

这意味着重写Equals允许在不同类型的两个对象之间进行比较(在某些情况下可能需要),但是,实现IEqualityComparer不会给予这种自由(在某些情况下也可能需要)。

在许多情况下,人们可能希望使用除100%等效之外的其他内容来使用Dictionary定位对象。 作为一个简单的例子,人们可能希望有一个以不区分大小写的方式匹配的字典。 实现这一目标的一种方法是在将字符串存储到字典或执行查找之前将字符串转换为规范的大写forms。 另一种方法是为字典提供IEqualityComparer ,它将计算哈希码并在某种与案例无关的函数中检查相等性。 在某些情况下,将字符串转换为规范forms并尽可能使用该forms将更有效,但在其他情况下,仅将字符串存储为其原始forms更有效。 我希望.NET的一个function是提高这些词典的实用性,这将是一种请求与给定键相关联的实际键对象的方法(因此,如果字典包含字符串"WowZo"作为键,则可以查找"wowzo"并得到"WowZo" ;遗憾的是,如果TValue不包含冗余引用,则检索实际密钥对象的唯一方法是枚举整个集合。

另一种情况是,有一种替代的比较方法可能是有用的,当一个对象持有对一个可变类型的实例的引用时,但永远不会将该实例暴露给任何可能使其变异的实例。 通常,两个包含相同值序列的int[]实例将不可互换,因为将来可能会将其中一个或两个更改为包含不同的值。 另一方面,如果将使用字典来保存和查找int[]值,则每个字段将是Universe中任何位于int[]实例的唯一引用,并且如果没有任何实例将被修改也没有暴露于外部代码,将相同的数组视为具有相同的值序列可能是有用的。 由于Array.Equals测试严格等价(引用相等),因此有必要使用其他一些方法来测试数组的等价性。