Existe uma maneira melhor para implementar Equals para objeto com lotes de campos?
-
11-09-2019 - |
Pergunta
ver também Hows para verificação rápida se os dados transferir dois objetos têm o mesmo propriedades em C #?
Eu tenho muita Transferência Data Objects (DTO) que cada um contém lotes de campos simples . Eu preciso implementar Equals em todos eles (para que eu possa escrever alguns testes de unidade off transportá-los var WCF).
O código que estou usando é:
public override bool Equals(object rhs)
{
RequestArguments other = rhs as RequestArguments;
return
other != null &&
other.m_RequestId.Equals(RequestId) &&
other.m_Type.Equals(m_Type) &&
other.m_Parameters.Equals(m_Parameters) &&
other.m_user.Equals(m_user);
}
Deve haver uma maneira melhor! ... (listando todos os campos é bastante pedindo erros e problemas de manutenção)
por exemplo. temos objeto. MemberwiseClone () para ajudar com o caso Clonagem (), mas eu não consigo encontrar nada para ajudar com Equals. Estamos executando em confiança total para que uma solução baseada reflexão é uma resposta, mas eu prefiro não reinventar a roda.
(Desculpe, mas não gerar o DTO a partir de uma linguagem específica de domínio de outra forma esse tipo de coisa seria fácil! Também eu não sou capaz de mudar o sistema de compilação para adicionar mais um passo)
Solução
Engraçado você perguntar, eu recentemente publicado algum código para fazer exatamente isso. Confira o meu MemberwiseEqualityComparer para ver se ele se adapta às suas necessidades.
É muito fácil de usar e bastante eficiente também. Ele usa IL-emita para gerar os Iguais inteiras e função GetHashCode na primeira execução (uma vez para cada tipo usado). Ele irá comparar cada campo (privada ou pública) do objeto determinado usando o comparador de igualdade padrão para esse tipo (EqualityComparer.Default). Temos vindo a usá-lo em produção por um tempo e parece estável, mas eu vou deixar nenhuma garantia =)
Ela cuida de todos os Edge-casos os pescy que raramente pensa quando você está rolando o seu próprio método equals (ou seja, você não pode comparer seu próprio objeto com nulo, a menos que você tenha em caixa-lo em um objeto primeiro e lote está fora mais problemas nulos-relacionada).
Eu estive significado para escrever um post sobre isso, mas não tivemos tempo para isso ainda. O código é um pouco situação irregular, mas se você como se eu pudesse limpá-lo um pouco.
public override int GetHashCode()
{
return MemberwiseEqualityComparer<Foo>.Default.GetHashCode(this);
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
return Equals(obj as Foo);
}
public override bool Equals(Foo other)
{
return MemberwiseEqualityComparer<Foo>.Default.Equals(this, other);
}
O MemberwiseEqualityComparer é liberado sob a MIT licença meaining você pode fazer praticamente o que quiser com ele, incluindo usá-lo em soluções proprietárias, sem alterar-lhe licenciar um pouco.
Outras dicas
Uma opção é usar o reflexo para obter todos os campos disponíveis e, em seguida, obter e comparar os seus valores sobre os objetos desejados. Isto lhe daria uma solução genérica, mas você teria bastante trabalho a fazer, provavelmente usando hashes como Alex sugere é uma solução mais limpa.
Editar : Aqui está um exemplo simples de comparar objetos usando reflexão, ele olha para propriedades em vez de campos, mas você começa a idéia: http://www.willasrari.com/blog/use-systemreflection-for-comparing-custom-objects/ 000257.aspx
Você pode ter um conceito de um hash objeto - sempre que um objeto muda, você paga o preço de atualizar o hash (onde o hash é, literalmente, um hash de todas as propriedades concatenadas). Então, se você tem um monte de objetos que raramente mudam, é realmente barato para compará-los. O preço, é claro, é pago no momento objeto edição.
Editar : desculpe, eu não notei que você está pedindo para o teste de serialização. Portanto, esta abordagem definitivamente não funciona para você.
Não há outra maneira "suja". Se o objeto é de qualquer maneira serializado, você pode serialize -los e comparar os fluxos resultantes.
Este é um pouco lento, mas deve ser bastante confiável e fácil de implementar.
Estamos fazendo isso algumas vezes para verificar se alguém mudou todos os dados em um editor.