Esto es lo que se me ocurrió como método en una clase heredada por muchas de mis otras clases. La idea es que permita la comparación simple entre propiedades de Objetos del mismo Tipo.
Ahora, esto funciona, pero en aras de mejorar la calidad de mi código, pensé en tirarlo para su escrutinio. ¿Cómo puede ser mejor / más 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
fuente
fuente
Respuestas:
Estaba buscando un fragmento de código que hiciera algo similar para ayudar con la escritura de la prueba unitaria. Esto es lo que terminé usando.
EDITAR:
El mismo código que el anterior, pero utiliza los métodos LINQ y Extension:
fuente
ACTUALIZACIÓN: La última versión de Compare-Net-Objects se encuentra en GitHub , tiene el paquete NuGet y el Tutorial . Se puede llamar como
O si necesita cambiar alguna configuración, use
La lista completa de parámetros configurables está en ComparisonConfig.cs
Respuesta original:
Las limitaciones que veo en tu código:
El más importante es que no hace una comparación de objetos profunda.
No hace una comparación elemento por elemento en caso de que las propiedades sean listas o contengan listas como elementos (esto puede ir en n niveles).
No tiene en cuenta que algún tipo de propiedades no deben ser comparadas (por ejemplo, una propiedad Func utilizada con fines de filtrado, como la de la clase PagedCollectionView).
No realiza un seguimiento de las propiedades que realmente eran diferentes (para que pueda mostrarlas en sus afirmaciones).
Hoy estaba buscando alguna solución con fines de prueba unitaria para hacer una comparación profunda propiedad por propiedad y terminé usando: http://comparenetobjects.codeplex.com .
Es una biblioteca gratuita con una sola clase que puedes usar así:
Además, se puede volver a compilar fácilmente para Silverlight. Simplemente copie la clase en un proyecto de Silverlight y elimine una o dos líneas de código para las comparaciones que no están disponibles en Silverlight, como la comparación de miembros privados.
fuente
IgnoreObjectTypes
configuración puede ser útil cuando hay diferentes tipos.DifferencesString
ha quedado obsoleto en la clase CompareObjects. Pero ahora puede obtener eso del ComparisonResult en su lugar:var r = compareObjects.Compare(objectA, objectB); Assert.IsTrue(r.AreEqual, r.DifferencesString);
Creo que sería mejor seguir el patrón de Ignorar objeto # Igual ()
Para una mejor descripción: Lea el C # efectivo de Bill Wagner - Elemento 9, creo
Actualización-diciembre de 2011:
fuente
Si el rendimiento no importa, puede serializarlos y comparar los resultados:
fuente
Creo que la respuesta de Big T fue bastante buena, pero faltaba la comparación profunda, así que la modifiqué un poco:
fuente
Agregaría la siguiente línea al método PublicInstancePropertiesEqual para evitar errores de copiar y pegar:
fuente
¿Anula .ToString () en todos sus objetos que están en las propiedades? De lo contrario, esa segunda comparación podría volverse nula.
Además, en esa segunda comparación, estoy indeciso sobre la construcción de! (A == B) en comparación con (A! = B), en términos de legibilidad dentro de seis meses / dos años. La línea en sí es bastante ancha, lo cual está bien si tiene un monitor ancho, pero es posible que no se imprima muy bien. (quisquilloso)
¿Todos sus objetos siempre usan propiedades de modo que este código funcione? ¿Podría haber algunos datos internos no propietarios que podrían ser diferentes de un objeto a otro, pero todos los datos expuestos son iguales? Estoy pensando en algunos datos que podrían cambiar con el tiempo, como dos generadores de números aleatorios que llegan al mismo número en un punto, pero van a producir dos secuencias de información diferentes, o simplemente cualquier dato que no quede expuesto. a través de la interfaz de propiedad.
fuente
Si solo está comparando objetos del mismo tipo o más abajo en la cadena de herencia, ¿por qué no especificar el parámetro como su tipo base, en lugar de como objeto?
También realice comprobaciones nulas en el parámetro.
Además, haría uso de 'var' solo para hacer que el código sea más legible (si es el código c # 3)
Además, si el objeto tiene tipos de referencia como propiedades, entonces solo está llamando a ToString () sobre ellos, lo que realmente no compara valores. Si ToString no se sobrescribe, solo devolverá el nombre del tipo como una cadena que podría devolver falsos positivos.
fuente
Lo primero que sugeriría sería dividir la comparación real para que sea un poco más legible (también he sacado el ToString (), ¿es necesario?):
La siguiente sugerencia sería minimizar el uso de la reflexión tanto como sea posible; es realmente lento. Quiero decir, muy lento. Si va a hacer esto, le sugiero que almacene en caché las referencias de propiedad. No estoy muy familiarizado con la API de Reflection, así que si esto está un poco apagado, simplemente ajústelo para que se compile:
Sin embargo, debo decir que estoy de acuerdo con los demás carteles. Esto huele a perezoso e ineficaz. En su lugar, debería implementar IComparable :-).
fuente
aquí se revisa uno para tratar nulo = nulo como igual
fuente
Terminé haciendo esto:
Uso:
Actualizar
Si desea ignorar algunas propiedades por nombre:
Uso:
fuente
Puede optimizar su código llamando a GetProperties solo una vez por tipo:
fuente
Para completar, quiero agregar una referencia a http://www.cyotek.com/blog/comparing-the-properties-of-two-objects-via-reflection Tiene una lógica más completa que la mayoría de las otras respuestas en esta página.
Sin embargo, prefiero la biblioteca Compare-Net-Objects https://github.com/GregFinzer/Compare-Net-Objects (referido por la respuesta de Liviu Trifoi ) La biblioteca tiene el paquete NuGet http://www.nuget.org/packages/ CompareNETObjects y múltiples opciones para configurar.
fuente
Asegúrese de que los objetos no lo sean
null
.Tener
obj1
yobj2
:fuente
Esto funciona incluso si los objetos son diferentes. podría personalizar los métodos en la clase de utilidades, tal vez también desee comparar propiedades privadas ...
fuente
Actualización sobre la respuesta de Liviu anterior: CompareObjects.DifferencesString ha quedado obsoleto.
Esto funciona bien en una prueba unitaria:
fuente
Assert.IsTrue(result.AreEqual, result.DifferencesString);
Este método obtendrá
properties
de la clase y comparará los valores de cada unoproperty
. Si alguno de los valores es diferente, lo seráreturn false
, de lo contrario lo seráreturn true
.Uso:
bool isEqual = Compare<Employee>(Object1, Object2)
fuente
Para ampliar la respuesta de @nawfal: s, lo uso para probar objetos de diferentes tipos en mis pruebas unitarias para comparar nombres de propiedades iguales. En mi caso, entidad de base de datos y DTO.
Usado así en mi prueba;
fuente
a veces no desea comparar todas las propiedades públicas y desea comparar solo el subconjunto de ellas, por lo que en este caso puede mover la lógica para comparar la lista deseada de propiedades con la clase abstracta
y usa esta clase abstracta más tarde para comparar los objetos
fuente
mi solución inspirada en la respuesta de Aras Alenin anterior, donde agregué un nivel de comparación de objetos y un objeto personalizado para obtener resultados de comparación. También estoy interesado en obtener el nombre de la propiedad con el nombre del objeto:
Usando la siguiente clase para almacenar resultados de comparación
Y una prueba unitaria de muestra:
fuente