Mar*_*wie 20 c# inheritance iequatable
我知道我总是必须覆盖Equals(object)
和GetHashCode()
实施时IEquatable<T>.Equals(T)
.
但是,我不明白,为什么在某些情况下Equals(object)
胜过通用Equals(T)
.
例如,为什么会发生以下情况?如果我声明IEquatable<T>
一个接口并X
为它实现一个具体的类型,那么在将这些类型的项目相互比较时,将Equals(object)
调用general Hashset<X>
.在其中至少一个边被强制转换为接口的所有其他情况下,Equals(T)
调用正确的.
这是一个代码示例来演示:
public interface IPerson : IEquatable<IPerson> { }
//Simple example implementation of Equals (returns always true)
class Person : IPerson
{
public bool Equals(IPerson other)
{
return true;
}
public override bool Equals(object obj)
{
return true;
}
public override int GetHashCode()
{
return 0;
}
}
private static void doEqualityCompares()
{
var t1 = new Person();
var hst = new HashSet<Person>();
var hsi = new HashSet<IPerson>();
hst.Add(t1);
hsi.Add(t1);
//Direct comparison
t1.Equals(t1); //IEquatable<T>.Equals(T)
hst.Contains(t1); //Equals(object) --> why? both sides inherit of IPerson...
hst.Contains((IPerson)t1); //IEquatable<T>.Equals(T)
hsi.Contains(t1); //IEquatable<T>.Equals(T)
hsi.Contains((IPerson)t1); //IEquatable<T>.Equals(T)
}
Run Code Online (Sandbox Code Playgroud)
Ser*_*rvy 21
HashSet<T>
EqualityComparer<T>.Default
在没有提供比较器时调用以获取默认的相等比较器.
EqualityComparer<T>.Default
确定是否T
实施IEquatable<T>
.如果是,它使用它,如果不是,它使用object.Equals
和object.GetHashCode
.
你的Person
对象IEquatable<IPerson>
没有实现IEquatable<Person>
.
当你有一个HashSet<Person>
它最终检查是否Person
是一个IEquatable<Person>
,它不是,所以它使用object
方法.
当你HashSet<IPerson>
检查它是否IPerson
是一个IEquatable<IPerson>
,它是什么,所以它使用这些方法.
至于其余的情况,为什么这行:
hst.Contains((IPerson)t1);
Run Code Online (Sandbox Code Playgroud)
调用IEquatable
Equals
方法,即使它调用了HashSet<Person>
.在这里你调用Contains
一个HashSet<Person>
和传递的IPerson
. HashSet<Person>.Contains
要求参数为a Person
; 一个IPerson
不是一个有效的论点.但是,a HashSet<Person>
也是一个IEnumerable<Person>
,并且由于IEnumerable<T>
是协变的,这意味着它可以被视为一个IEnumerable<IPerson>
,它有一个Contains
扩展方法(通过LINQ)接受IPerson
一个参数.
IEnumerable.Contains
EqualityComparer<T>.Default
当没有提供时,它也用于获得它的相等比较器.在这个方法调用的情况下,我们实际上正在调用Contains
一个IEnumerable<IPerson>
,这意味着EqualityComparer<IPerson>.Default
检查是否IPerson
是一个IEquatable<IPerson>
,它是什么,以便Equals
调用该方法.