C'est ce que j'ai proposé comme méthode sur une classe héritée par beaucoup de mes autres classes. L'idée est qu'elle permet la simple comparaison entre les propriétés des objets du même type.
Maintenant, cela fonctionne - mais dans l'intérêt d'améliorer la qualité de mon code, j'ai pensé que je le jetterais pour examen. Comment peut-il être meilleur / plus efficace / 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;
}
Réponses:
Je cherchais un extrait de code qui ferait quelque chose de similaire pour aider à écrire un test unitaire. Voici ce que j'ai fini par utiliser.
ÉDITER:
Même code que ci-dessus mais utilise les méthodes LINQ et Extension:
la source
MISE À JOUR: La dernière version de Compare-Net-Objects se trouve sur GitHub , contient le package NuGet et le didacticiel . Cela peut être appelé comme
Ou si vous avez besoin de modifier une configuration, utilisez
La liste complète des paramètres configurables se trouve dans ComparisonConfig.cs
Réponse originale:
Les limitations que je vois dans votre code:
Le plus important est qu'il ne fait pas de comparaison d'objets approfondie.
Il ne fait pas de comparaison élément par élément dans le cas où les propriétés sont des listes ou contiennent des listes en tant qu'éléments (cela peut aller à n niveaux).
Il ne tient pas compte du fait que certains types de propriétés ne doivent pas être comparés (par exemple une propriété Func utilisée à des fins de filtrage, comme celle de la classe PagedCollectionView).
Il ne garde pas trace des propriétés réellement différentes (vous pouvez donc les montrer dans vos assertions).
Je cherchais aujourd'hui une solution à des fins de test unitaire pour faire une comparaison approfondie propriété par propriété et j'ai fini par utiliser: http://comparenetobjects.codeplex.com .
C'est une bibliothèque gratuite avec une seule classe que vous pouvez simplement utiliser comme ceci:
En outre, il peut être facilement recompilé pour Silverlight. Copiez simplement la classe dans un projet Silverlight et supprimez une ou deux lignes de code pour les comparaisons qui ne sont pas disponibles dans Silverlight, comme la comparaison des membres privés.
la source
IgnoreObjectTypes
réglage peut être utile lorsqu'il existe différents types.DifferencesString
a été abandonné dans la classe CompareObjects. Mais maintenant, vous pouvez obtenir cela à partir du résultat de comparaison à la place:var r = compareObjects.Compare(objectA, objectB); Assert.IsTrue(r.AreEqual, r.DifferencesString);
Je pense qu'il serait préférable de suivre le modèle pour Override Object # Equals ()
Pour une meilleure description: Lisez le C # effectif de Bill Wagner - Point 9 Je pense
Mise à jour-décembre 2011:
la source
Si les performances n'ont pas d'importance, vous pouvez les sérialiser et comparer les résultats:
la source
Je pense que la réponse de Big T était assez bonne, mais la comparaison approfondie manquait, alors je l'ai légèrement modifiée:
la source
J'ajouterais la ligne suivante à la méthode PublicInstancePropertiesEqual pour éviter les erreurs de copier-coller:
la source
Remplacez-vous .ToString () sur tous vos objets qui se trouvent dans les propriétés? Sinon, cette deuxième comparaison pourrait revenir avec null.
De plus, dans cette deuxième comparaison, je suis sur la clôture de la construction de! (A == B) par rapport à (A! = B), en termes de lisibilité dans six mois / deux ans. La ligne elle-même est assez large, ce qui est normal si vous avez un écran large, mais peut ne pas s'imprimer très bien. (pinailler)
Tous vos objets utilisent-ils toujours des propriétés telles que ce code fonctionnera? Pourrait-il y avoir des données internes non propriétaires qui pourraient être différentes d'un objet à l'autre, mais toutes les données exposées sont les mêmes? Je pense à certaines données qui pourraient changer avec le temps, comme deux générateurs de nombres aléatoires qui atteignent le même nombre à un moment donné, mais qui vont produire deux séquences d'informations différentes, ou n'importe quelles données qui ne sont pas exposées via l'interface de propriété.
la source
Si vous ne comparez que des objets du même type ou plus bas dans la chaîne d'héritage, pourquoi ne pas spécifier le paramètre comme type de base plutôt que comme objet?
Faites également des vérifications nulles sur le paramètre.
De plus, j'utiliserais 'var' juste pour rendre le code plus lisible (si son code c # 3)
De plus, si l'objet a des types de référence comme propriétés, vous appelez simplement ToString () sur eux, ce qui ne compare pas vraiment les valeurs. Si ToString n'est pas écrasé, il retournera simplement le nom du type sous forme de chaîne qui pourrait renvoyer des faux positifs.
la source
La première chose que je suggérerais serait de diviser la comparaison réelle afin qu'elle soit un peu plus lisible (j'ai également retiré le ToString () - est-ce nécessaire?):
La prochaine suggestion serait de minimiser l'utilisation de la réflexion autant que possible - c'est vraiment lent. Je veux dire, vraiment lent. Si vous envisagez de faire cela, je vous suggère de mettre en cache les références de propriété. Je ne suis pas intimement familier avec l'API Reflection, donc si ce n'est pas le cas, ajustez-le pour le faire compiler:
Cependant, je dois dire que je suis d'accord avec les autres affiches. Cela sent paresseux et inefficace. Vous devriez plutôt implémenter IComparable :-).
la source
ici est révisé un pour traiter null = null comme égal
la source
J'ai fini par faire ceci:
Usage:
Mettre à jour
Si vous souhaitez ignorer certaines propriétés par leur nom:
Usage:
la source
Vous pouvez optimiser votre code en appelant GetProperties une seule fois par type:
la source
Pour être complet, je veux ajouter une référence à http://www.cyotek.com/blog/comparing-the-properties-of-two-objects-via-reflection Il a une logique plus complète que la plupart des autres réponses sur cette page.
Cependant , je préfère COMPARE-Net-bibliothèque d' objets https://github.com/GregFinzer/Compare-Net-Objects (ci -après par Liviu Trifoi de réponse )
La bibliothèque a package NuGet http://www.nuget.org/packages/ CompareNETObjects et plusieurs options à configurer.
la source
Assurez-vous que les objets ne le sont pas
null
.Avoir
obj1
etobj2
:la source
Cela fonctionne même si les objets sont différents. vous pouvez personnaliser les méthodes dans la classe des utilitaires, peut-être souhaitez-vous également comparer les propriétés privées ...
la source
Mise à jour sur la réponse de Liviu ci-dessus - CompareObjects.DifferencesString est obsolète.
Cela fonctionne bien dans un test unitaire:
la source
Assert.IsTrue(result.AreEqual, result.DifferencesString);
Cette méthode obtiendra
properties
de la classe et comparera les valeurs pour chacunproperty
. Si l'une des valeurs est différente, elle le serareturn false
, sinon elle le serareturn true
.Usage:
bool isEqual = Compare<Employee>(Object1, Object2)
la source
Pour développer la réponse de @nawfal: s, je l'utilise pour tester des objets de différents types dans mes tests unitaires afin de comparer des noms de propriétés égaux. Dans mon cas, entité de base de données et DTO.
Utilisé comme ça dans mon test;
la source
Parfois, vous ne voulez pas comparer toutes les propriétés publiques et ne voulez comparer que le sous-ensemble d'entre elles, donc dans ce cas, vous pouvez simplement déplacer la logique pour comparer la liste de propriétés souhaitée à la classe abstraite
et utilisez cette classe abstraite plus tard pour comparer les objets
la source
ma solution est inspirée de la réponse d'Aras Alenin ci-dessus où j'ai ajouté un niveau de comparaison d'objets et un objet personnalisé pour les résultats de comparaison. Je suis également intéressé à obtenir le nom de la propriété avec le nom de l'objet:
Utilisation de la classe suivante pour stocker les résultats de comparaison
Et un exemple de test unitaire:
la source