EqualityComparer<T>.Mal-entendido padrão?
-
11-12-2019 - |
Pergunta
eu tenho uma aula Person
, ele implementa o método Equals() de IEquatable<Person>
(também substitui Object.Equals
método, vamos ignorar o método GetHashcode() por enquanto)
class Person : IEquatable<Person>
{
public string Name { get; set; }
public bool Equals(Person other)
{
return this.Name == other.Name;
}
public override bool Equals(object obj)
{
var person = obj as Person;
return person != null && person.Name == Name;
}
}
OK vamos começar:
Person p1 = new Person() { Name = "a" };
Person p2 = new Person() { Name = "a" };
List<Person> lst1 = new List<Person>() { p1 };
List<Person> lst2 = new List<Person>() { p2 };
Vamos falar sobre esta linha:
bool b = lst1.SequenceEqual(lst2, EqualityComparer<Person>.Default);
Estou com dificuldade para entender esta parte:
EqualityComparer<Person>.Default
Eu ouvi isso EqualityComparer<Person>.Default
irá verificar se a classe está implementando IEquatable
- levará o Equals(Person other)
Método e não o Equals(object obj)
. tem a vantagem de evitar o boxe
mas
o Equals(Person other)
correrá com ou sem FORA EqualityComparer<Person>.Default
(porque está implementando IEquatable)
Então, de que boxe estamos falando?não há!
A única vez que Equals(object obj)
será executado é quando:
bool b = lst1.SequenceEqual(lst2,EqualityComparer<Object>.Default);
Mas Eu sou um programador!Eu nunca enviarei um object
quando na verdade é um Person
!
o que estou perdendo?Estou tendo problemas para entender o benefício aqui de EqualityComparer<Object>.Default
.Alguém pode me dar um exemplo para provar que estou errado?
Solução
Se você passar null
como o segundo parâmetro ou se você não passar nenhum segundo argumento (que é basicamente o mesmo), a implementação de SequenceEquals chamará EqualityComparer<T>.Default
em si (descompilar Enumerable
para ver isso).Isso explica por que você não vê diferença se fornece EqualityComparer<T>.Default
ou não.
Então no final o segundo parâmetro só faz sentido se você quiser usar um comparador de igualdade outro que não seja EqualityComparer<T>.Default
.
Outras dicas
Que você pode passar IEqualityComparer<object>.Default
é um efeito de contravariância genérica, adicionado no .NET 4.
Essencialmente, um IEqualityComparer<BaseType>
pode ser usado sempre que um IEqualityComparer<DerivedType>
é obrigatório, onde DerivedType : BaseType
.Desde Person
deriva de Object
, isso significa que um IEqualityComparer<Object>
pode ser usado onde quer que IEqualityComparer<Person>
é necessário.
A resposta está aqui: http://msdn.microsoft.com/en-us/library/ms131187(v=vs.110).aspx
Para um tipo de valor, você deve sempre implementar IEquatable e substituir Object.Equals(Object) para obter melhor desempenho.Object.Equals enquadra os tipos de valor e depende da reflexão para comparar dois valores quanto à igualdade.Tanto a implementação de Equals quanto a substituição de Object.Equals devem retornar resultados consistentes.
Se você não substituir Equals e GetHashCode, EqualityComparer.Default cuidará disso para você.