Isso é o que eu criei como um método em uma classe herdada por muitas das minhas outras classes. A ideia é que ele permita a comparação simples entre propriedades de objetos do mesmo tipo.
Agora, isso funciona - mas no interesse de melhorar a qualidade do meu código, pensei em jogá-lo fora para análise. Como pode ser melhor / mais eficiente / etc.?
/// <summary>
/// Compare property values (as strings)
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public bool PropertiesEqual(object comparisonObject)
{
Type sourceType = this.GetType();
Type destinationType = comparisonObject.GetType();
if (sourceType == destinationType)
{
PropertyInfo[] sourceProperties = sourceType.GetProperties();
foreach (PropertyInfo pi in sourceProperties)
{
if ((sourceType.GetProperty(pi.Name).GetValue(this, null) == null && destinationType.GetProperty(pi.Name).GetValue(comparisonObject, null) == null))
{
// if both are null, don't try to compare (throws exception)
}
else if (!(sourceType.GetProperty(pi.Name).GetValue(this, null).ToString() == destinationType.GetProperty(pi.Name).GetValue(comparisonObject, null).ToString()))
{
// only need one property to be different to fail Equals.
return false;
}
}
}
else
{
throw new ArgumentException("Comparison object must be of the same type.","comparisonObject");
}
return true;
}
c#
object
properties
comparison
Nailitdown
fonte
fonte
Respostas:
Eu estava procurando um trecho de código que faria algo semelhante para ajudar a escrever o teste de unidade. Aqui está o que acabei usando.
EDITAR:
Mesmo código acima, mas usa métodos LINQ e extensão:
fonte
ATUALIZAÇÃO: A versão mais recente do Compare-Net-Objects está localizada no GitHub , tem o pacote NuGet e o Tutorial . Pode ser chamado de
Ou se você precisar alterar alguma configuração, use
A lista completa de parâmetros configuráveis está em ComparisonConfig.cs
Resposta original:
As limitações que vejo em seu código:
O maior deles é que ele não faz uma comparação profunda de objetos.
Ele não faz uma comparação elemento por elemento no caso de propriedades serem listas ou contêm listas como elementos (isso pode ir em n níveis).
Não leva em consideração que alguns tipos de propriedades não devem ser comparados (por exemplo, uma propriedade Func usada para fins de filtragem, como a da classe PagedCollectionView).
Ele não controla quais propriedades realmente eram diferentes (para que você possa mostrar em suas asserções).
Eu estava procurando hoje por alguma solução para fins de teste de unidade para fazer comparação profunda propriedade por propriedade e acabei usando: http://comparenetobjects.codeplex.com .
É uma biblioteca gratuita com apenas uma classe que você pode simplesmente usar assim:
Além disso, pode ser facilmente recompilado para o Silverlight. Basta copiar uma classe em um projeto Silverlight e remover uma ou duas linhas de código para comparações que não estão disponíveis no Silverlight, como comparação de membros privados.
fonte
IgnoreObjectTypes
configuração pode ser útil quando existem diferentes tipos.DifferencesString
foi descontinuado na classe CompareObjects. Mas agora você pode obter isso no ComparisonResult:var r = compareObjects.Compare(objectA, objectB); Assert.IsTrue(r.AreEqual, r.DifferencesString);
Acho que seria melhor seguir o padrão para Substituir Objeto # Equals ()
Para uma descrição melhor: Leia o C # Efetivo de Bill Wagner - Item 9, eu acho
Atualização - dezembro de 2011:
fonte
Se o desempenho não importa, você pode serializá-los e comparar os resultados:
fonte
Acho que a resposta do Big T foi muito boa, mas faltou uma comparação profunda, então ajustei um pouco:
fonte
Eu adicionaria a seguinte linha ao método PublicInstancePropertiesEqual para evitar erros de copiar e colar:
fonte
Você substitui .ToString () em todos os seus objetos que estão nas propriedades? Caso contrário, essa segunda comparação poderia retornar com null.
Além disso, nessa segunda comparação, estou em dúvida quanto à construção de! (A == B) em comparação com (A! = B), em termos de legibilidade daqui a seis meses / dois anos. A linha em si é bem larga, o que é bom se você tiver um monitor largo, mas pode não imprimir muito bem. (nitpick)
Todos os seus objetos estão sempre usando propriedades para que esse código funcione? Pode haver alguns dados internos não proprietários que podem ser diferentes de um objeto para outro, mas todos os dados expostos são os mesmos? Estou pensando em alguns dados que podem mudar ao longo do tempo, como dois geradores de números aleatórios que acertam o mesmo número em um ponto, mas vão produzir duas sequências diferentes de informações ou apenas quaisquer dados que não sejam expostos por meio da interface de propriedade.
fonte
Se você está apenas comparando objetos do mesmo tipo ou mais abaixo na cadeia de herança, por que não especificar o parâmetro como seu tipo base, em vez de objeto?
Também faça verificações nulas no parâmetro.
Além disso, eu faria uso de 'var' apenas para tornar o código mais legível (se for um código c # 3)
Além disso, se o objeto tiver tipos de referência como propriedades, você está apenas chamando ToString () neles, o que realmente não compara valores. Se ToString não for substituído, ele apenas retornará o nome do tipo como uma string que pode retornar falsos positivos.
fonte
A primeira coisa que eu sugeriria seria dividir a comparação real para que seja um pouco mais legível (também retirei o ToString () - isso é necessário?):
A próxima sugestão seria minimizar o uso de reflexão tanto quanto possível - é muito lento. Quer dizer, muito lento. Se você for fazer isso, sugiro armazenar em cache as referências de propriedade. Não estou intimamente familiarizado com a Reflection API, então, se ela estiver um pouco errada, apenas ajuste para compilar:
No entanto, devo dizer que concordo com os outros cartazes. Isso tem um cheiro preguiçoso e ineficiente. Você deve implementar IComparable ao invés :-).
fonte
aqui é revisado um para tratar null = null como igual
fonte
Acabei fazendo isso:
Uso:
Atualizar
Se você deseja ignorar algumas propriedades pelo nome:
Uso:
fonte
Você pode otimizar seu código chamando GetProperties apenas uma vez por tipo:
fonte
Para completar, desejo adicionar referência a http://www.cyotek.com/blog/comparing-the-properties-of-two-objects-via-reflection. Ele tem uma lógica mais completa do que a maioria das outras respostas nesta página.
No entanto eu prefiro Compare-Net-Objects biblioteca https://github.com/GregFinzer/Compare-Net-Objects (referido por Liviu Trifoi 's resposta )
A biblioteca tem pacote NuGet http://www.nuget.org/packages/ CompareNETObjects e várias opções para configurar.
fonte
Certifique-se de que os objetos não sejam
null
.Tendo
obj1
eobj2
:fonte
Isso funciona mesmo se os objetos forem diferentes. você pode personalizar os métodos na classe de utilitários, talvez você queira comparar propriedades privadas também ...
fonte
Atualização da resposta de Liviu acima - CompareObjects.DifferencesString foi descontinuado.
Isso funciona bem em um teste de unidade:
fonte
Assert.IsTrue(result.AreEqual, result.DifferencesString);
Este método obterá
properties
da classe e comparará os valores de cada umaproperty
. Se algum dos valores for diferente, seráreturn false
, do contrário seráreturn true
.Uso:
bool isEqual = Compare<Employee>(Object1, Object2)
fonte
Para expandir a resposta de @nawfal: s, eu uso isso para testar objetos de diferentes tipos em meus testes de unidade para comparar nomes de propriedades iguais. No meu caso, entidade de banco de dados e DTO.
Usado assim no meu teste;
fonte
às vezes você não deseja comparar todas as propriedades públicas e deseja comparar apenas o subconjunto delas, então, neste caso, você pode apenas mover a lógica para comparar a lista desejada de propriedades para a classe abstrata
e usar esta classe abstrata mais tarde para comparar os objetos
fonte
minha solução inspirada na resposta de Aras Alenin acima, onde adicionei um nível de comparação de objetos e um objeto personalizado para resultados de comparação. Também estou interessado em obter o nome da propriedade com o nome do objeto:
Usando a seguinte classe para armazenar resultados de comparação
E um teste de unidade de amostra:
fonte