Dies ist, was ich als Methode für eine Klasse entwickelt habe, die von vielen meiner anderen Klassen geerbt wurde. Die Idee ist, dass es den einfachen Vergleich zwischen Eigenschaften von Objekten desselben Typs ermöglicht.
Nun, das funktioniert - aber um die Qualität meines Codes zu verbessern, dachte ich, ich würde ihn zur Überprüfung wegwerfen. Wie kann es besser / effizienter / etc. Sein?
/// <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
quelle
quelle
Antworten:
Ich suchte nach einem Codeausschnitt, der etwas Ähnliches tun würde, um beim Schreiben von Komponententests zu helfen. Folgendes habe ich letztendlich verwendet.
BEARBEITEN:
Gleicher Code wie oben, verwendet jedoch die Methoden LINQ und Extension:
quelle
UPDATE: Die neueste Version von Compare-Net-Objects befindet sich auf GitHub und enthält das NuGet-Paket und das Tutorial . Es kann wie genannt werden
Oder verwenden Sie, wenn Sie eine Konfiguration ändern müssen
Die vollständige Liste der konfigurierbaren Parameter finden Sie in ComparisonConfig.cs
Ursprüngliche Antwort:
Die Einschränkungen, die ich in Ihrem Code sehe:
Das größte ist, dass es keinen tiefen Objektvergleich macht.
Es wird kein Element-für-Element-Vergleich durchgeführt, wenn Eigenschaften Listen sind oder Listen als Elemente enthalten (dies kann n-Ebenen sein).
Es wird nicht berücksichtigt, dass bestimmte Arten von Eigenschaften nicht verglichen werden sollten (z. B. eine Func-Eigenschaft, die zu Filterzwecken verwendet wird, wie die in der PagedCollectionView-Klasse).
Es wird nicht nachverfolgt, welche Eigenschaften tatsächlich unterschiedlich waren (sodass Sie dies in Ihren Behauptungen anzeigen können).
Ich habe heute nach einer Lösung für Unit-Test-Zwecke gesucht, um einen tiefen Vergleich von Eigenschaften zu Eigenschaften durchzuführen, und am Ende habe ich Folgendes verwendet: http://comparenetobjects.codeplex.com .
Es ist eine kostenlose Bibliothek mit nur einer Klasse, die Sie einfach so verwenden können:
Es kann auch leicht für Silverlight neu kompiliert werden. Kopieren Sie einfach die eine Klasse in ein Silverlight-Projekt und entfernen Sie eine oder zwei Codezeilen für Vergleiche, die in Silverlight nicht verfügbar sind, wie z. B. den Vergleich privater Mitglieder.
quelle
IgnoreObjectTypes
Einstellung kann auch nützlich sein, wenn es verschiedene Typen gibt.DifferencesString
wurde in der CompareObjects-Klasse korrigiert. Aber jetzt können Sie das stattdessen aus dem Vergleichsergebnis erhalten:var r = compareObjects.Compare(objectA, objectB); Assert.IsTrue(r.AreEqual, r.DifferencesString);
Ich denke, es wäre am besten, dem Muster für Override Object # Equals () zu folgen.
Für eine bessere Beschreibung: Lesen Sie Bill Wagners effektives C # - Punkt 9, denke ich
Update-Dez 2011:
quelle
Wenn die Leistung keine Rolle spielt, können Sie sie serialisieren und die Ergebnisse vergleichen:
quelle
Ich denke, die Antwort von Big T war ziemlich gut, aber der tiefe Vergleich fehlte, also habe ich ihn ein wenig optimiert:
quelle
Ich würde der PublicInstancePropertiesEqual-Methode die folgende Zeile hinzufügen, um Fehler beim Kopieren und Einfügen zu vermeiden:
quelle
Überschreiben Sie .ToString () für alle Ihre Objekte in den Eigenschaften? Andernfalls könnte dieser zweite Vergleich mit null zurückkommen.
Auch in diesem zweiten Vergleich bin ich am Zaun über das Konstrukt von! (A == B) im Vergleich zu (A! = B) in Bezug auf die Lesbarkeit in sechs Monaten / zwei Jahren. Die Linie selbst ist ziemlich breit, was in Ordnung ist, wenn Sie einen breiten Monitor haben, aber möglicherweise nicht sehr gut drucken. (Nitpick)
Verwenden alle Ihre Objekte immer Eigenschaften, sodass dieser Code funktioniert? Könnte es einige interne, nicht besessene Daten geben, die sich von Objekt zu Objekt unterscheiden können, aber alle offengelegten Daten sind gleich? Ich denke an einige Daten, die sich im Laufe der Zeit ändern könnten, wie zwei Zufallszahlengeneratoren, die zufällig an einem Punkt dieselbe Zahl treffen, aber zwei verschiedene Informationssequenzen erzeugen, oder nur Daten, die nicht verfügbar gemacht werden über die Eigenschaftsschnittstelle.
quelle
Wenn Sie nur Objekte desselben Typs oder weiter unten in der Vererbungskette vergleichen, geben Sie den Parameter als Basistyp und nicht als Objekt an.
Führen Sie auch Nullprüfungen für den Parameter durch.
Außerdem würde ich 'var' verwenden, um den Code besser lesbar zu machen (wenn es sich um den C # 3-Code handelt).
Wenn das Objekt Referenztypen als Eigenschaften hat, rufen Sie einfach ToString () auf, wodurch die Werte nicht wirklich verglichen werden. Wenn ToString nicht überschrieben wird, wird nur der Typname als Zeichenfolge zurückgegeben, die falsch positive Ergebnisse zurückgeben kann.
quelle
Das erste, was ich vorschlagen würde, wäre, den tatsächlichen Vergleich so aufzuteilen, dass er etwas besser lesbar ist (ich habe auch den ToString () herausgenommen - wird das benötigt?):
Der nächste Vorschlag wäre, den Einsatz von Reflexion so gering wie möglich zu halten - es ist sehr langsam. Ich meine, sehr langsam. Wenn Sie dies tun, würde ich vorschlagen, die Eigenschaftsreferenzen zwischenzuspeichern. Ich bin mit der Reflection-API nicht sehr vertraut. Wenn dies nicht der Fall ist, passen Sie sie einfach an, damit sie kompiliert wird:
Ich muss jedoch sagen, dass ich den anderen Postern zustimme. Das riecht faul und ineffizient. Sie sollten stattdessen IComparable implementieren :-).
quelle
Hier wird eins überarbeitet, um null = null als gleich zu behandeln
quelle
Am Ende habe ich das gemacht:
Verwendung:
Aktualisieren
Wenn Sie einige Eigenschaften nach Namen ignorieren möchten:
Verwendung:
quelle
Sie können Ihren Code optimieren, indem Sie GetProperties nur einmal pro Typ aufrufen:
quelle
Der Vollständigkeit halber möchte ich auf http://www.cyotek.com/blog/comparing-the-properties-of-two-objects-via-reflection verweisen. Es hat eine vollständigere Logik als die meisten anderen Antworten auf dieser Seite.
Allerdings ziehe ich Vergleichen-Net-Objects - Bibliothek https://github.com/GregFinzer/Compare-Net-Objects (genannt von Liviu Trifoi ‚s Antwort )
Die Bibliothek hat NuGet Paket http://www.nuget.org/packages/ CompareNETObjects und mehrere zu konfigurierende Optionen.
quelle
Stellen Sie sicher, dass keine Objekte vorhanden sind
null
.Haben
obj1
undobj2
:quelle
Dies funktioniert auch dann, wenn die Objekte unterschiedlich sind. Sie können die Methoden in der Utilities-Klasse anpassen. Vielleicht möchten Sie auch private Eigenschaften vergleichen ...
quelle
Update zu Livius Antwort oben - CompareObjects.DifferencesString ist veraltet.
Dies funktioniert gut in einem Unit-Test:
quelle
Assert.IsTrue(result.AreEqual, result.DifferencesString);
Diese Methode wird
properties
aus der Klasse abgerufen und die Werte für jede Klasse verglichenproperty
. Wenn einer der Werte unterschiedlich ist, wird esreturn false
, sonst wird esreturn true
.Verwendung:
bool isEqual = Compare<Employee>(Object1, Object2)
quelle
Um die Antwort von @nawfal: s zu erweitern, verwende ich diese Option, um Objekte verschiedener Typen in meinen Komponententests zu testen und gleiche Eigenschaftsnamen zu vergleichen. In meinem Fall Datenbankentität und DTO.
Wird in meinem Test so verwendet.
quelle
Manchmal möchten Sie nicht alle öffentlichen Eigenschaften vergleichen und nur die Teilmenge von ihnen vergleichen. In diesem Fall können Sie also einfach die Logik verschieben, um die gewünschte Liste von Eigenschaften mit der abstrakten Klasse zu vergleichen
und verwenden Sie diese abstrakte Klasse später, um die Objekte zu vergleichen
quelle
Meine Lösung wurde von der obigen Antwort von Aras Alenin inspiriert, in der ich eine Ebene des Objektvergleichs und ein benutzerdefiniertes Objekt für Vergleichsergebnisse hinzugefügt habe. Ich bin auch daran interessiert, den Eigenschaftsnamen mit dem Objektnamen zu erhalten:
Verwenden der folgenden Klasse zum Speichern von Vergleichsergebnissen
Und ein Beispiel-Unit-Test:
quelle