Oto, co wymyśliłem jako metodę w klasie dziedziczonej przez wiele innych moich klas. Pomysł polega na tym, że pozwala na proste porównanie między właściwościami obiektów tego samego typu.
Teraz to działa - ale w interesie poprawy jakości mojego kodu pomyślałem, że wyrzucę go do sprawdzenia. Jak to może być lepsze / bardziej wydajne / itp.?
/// <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
źródło
źródło
Odpowiedzi:
Szukałem fragmentu kodu, który zrobiłby coś podobnego, aby pomóc w pisaniu testów jednostkowych. Oto, czego ostatecznie użyłem.
EDYTOWAĆ:
Ten sam kod jak powyżej, ale używa metod LINQ i Extension:
źródło
AKTUALIZACJA: Najnowsza wersja Compare-Net-Objects znajduje się w serwisie GitHub , zawiera pakiet NuGet i samouczek . Można to nazwać jak
Lub jeśli chcesz zmienić jakąś konfigurację, użyj
Pełna lista konfigurowalnych parametrów znajduje się w pliku CompareConfig.cs
Oryginalna odpowiedź:
Ograniczenia, które widzę w Twoim kodzie:
Największą z nich jest to, że nie wykonuje głębokiego porównania obiektów.
Nie wykonuje porównania elementu po elemencie w przypadku, gdy właściwości są listami lub zawierają listy jako elementy (może to mieć n-poziom).
Nie bierze pod uwagę, że nie należy porównywać niektórych typów właściwości (np. Właściwość Func używana do celów filtrowania, jak ta w klasie PagedCollectionView).
Nie śledzi, jakie właściwości faktycznie były różne (więc możesz pokazać w swoich asercjach).
Szukałem dzisiaj jakiegoś rozwiązania do celów testów jednostkowych, aby przeprowadzić głębokie porównanie właściwości według właściwości i ostatecznie skorzystałem z: http://comparenetobjects.codeplex.com .
Jest to darmowa biblioteka z tylko jedną klasą, której możesz po prostu użyć w następujący sposób:
Można go również łatwo ponownie skompilować dla Silverlight. Po prostu skopiuj jedną klasę do projektu Silverlight i usuń jeden lub dwa wiersze kodu dla porównań, które nie są dostępne w Silverlight, na przykład porównania prywatnych członków.
źródło
IgnoreObjectTypes
ustawienie może być przydatne, gdy istnieją różne typy.DifferencesString
został usunięty w klasie CompareObjects. Ale teraz możesz to uzyskać zvar r = compareObjects.Compare(objectA, objectB); Assert.IsTrue(r.AreEqual, r.DifferencesString);
Myślę, że najlepiej byłoby postępować zgodnie ze wzorem dla Override Object # Equals ()
Aby uzyskać lepszy opis: Przeczytaj efektywny C # Billa Wagnera - Myślę, że punkt 9
Aktualizacja - grudzień 2011:
źródło
Jeśli wydajność nie ma znaczenia, możesz je serializować i porównać wyniki:
źródło
Myślę, że odpowiedź Big T była całkiem dobra, ale brakowało głębokiego porównania, więc trochę go poprawiłem:
źródło
Dodałbym następujący wiersz do metody PublicInstancePropertiesEqual, aby uniknąć błędów kopiowania i wklejania:
źródło
Czy nadpisujesz .ToString () na wszystkich obiektach, które są we właściwościach? W przeciwnym razie to drugie porównanie mogłoby zwrócić wartość null.
Również w tym drugim porównaniu jestem na granicy co do konstrukcji! (A == B) w porównaniu z (A! = B), pod względem czytelności za sześć miesięcy / dwa lata od teraz. Sama linia jest dość szeroka, co jest w porządku, jeśli masz szeroki monitor, ale może nie drukować się dobrze. (czubek)
Czy wszystkie obiekty zawsze używają takich właściwości, że ten kod będzie działał? Czy mogą istnieć jakieś wewnętrzne, niezastrzeżone dane, które mogą się różnić w zależności od obiektu, ale wszystkie ujawnione dane są takie same? Myślę o niektórych danych, które mogą się zmieniać w czasie, na przykład dwa generatory liczb losowych, które zdarzają się trafiać w tę samą liczbę w jednym punkcie, ale zamierzają wygenerować dwie różne sekwencje informacji lub po prostu dane, które nie zostaną ujawnione poprzez interfejs właściwości.
źródło
Jeśli porównujesz tylko obiekty tego samego typu lub dalej w łańcuchu dziedziczenia, dlaczego nie określić parametru jako typu podstawowego, a nie obiektu?
Wykonaj również testy zerowe parametru.
Ponadto użyłbym `` var '' tylko po to, aby kod był bardziej czytelny (jeśli jest to kod C # 3)
Ponadto, jeśli obiekt ma typy referencyjne jako właściwości, to po prostu wywołujesz na nich ToString (), co tak naprawdę nie porównuje wartości. Jeśli ToString nie zostanie nadpisane, po prostu zwróci nazwę typu jako ciąg, który może zwrócić fałszywie dodatnie wartości.
źródło
Pierwszą rzeczą, którą zasugerowałbym, byłoby podzielenie rzeczywistego porównania, aby było nieco bardziej czytelne (wyjąłem również ToString () - czy to jest potrzebne?):
Następną sugestią byłoby maksymalne zminimalizowanie użycia odbicia - jest to naprawdę powolne. To znaczy naprawdę wolno. Jeśli masz zamiar to zrobić, sugerowałbym buforowanie odwołań do właściwości. Nie jestem dokładnie zaznajomiony z interfejsem API Reflection, więc jeśli jest trochę niesprawny, po prostu dostosuj go, aby go kompilować:
Muszę jednak powiedzieć, że zgadzam się z innymi plakatami. To pachnie leniwie i nieefektywnie. Zamiast tego powinieneś zaimplementować IComparable :-).
źródło
tutaj zmieniono jeden, aby traktować null = null jako równe
źródło
Skończyło się na tym:
Stosowanie:
Aktualizacja
Jeśli chcesz zignorować niektóre właściwości według nazwy:
Stosowanie:
źródło
Możesz zoptymalizować swój kod, wywołując GetProperties tylko raz dla każdego typu:
źródło
Dla kompletności chciałbym dodać odniesienie do http://www.cyotek.com/blog/comparing-the-properties-of-two-objects-via-reflection Ma bardziej kompletną logikę niż większość innych odpowiedzi na tej stronie.
Jednak wolę Porównaj-Net-Przedmioty biblioteka https://github.com/GregFinzer/Compare-Net-Objects (określone przez Liviu Trifoi „s odpowiedzi )
Biblioteka posiada pakiet Nuget http://www.nuget.org/packages/ CompareNETObjects i wiele opcji do skonfigurowania.
źródło
Upewnij się, że przedmioty nie są
null
.Posiadanie
obj1
iobj2
:źródło
Działa to nawet wtedy, gdy obiekty są różne. możesz dostosować metody w klasie narzędzi, może chcesz również porównać prywatne właściwości ...
źródło
Aktualizacja odpowiedzi Liviu powyżej - CompareObjects.DifferencesString został wycofany.
Działa to dobrze w teście jednostkowym:
źródło
Assert.IsTrue(result.AreEqual, result.DifferencesString);
Ta metoda pobierze
properties
klasę i porówna wartości dla każdej z nichproperty
. Jeśli którakolwiek z wartości jest inna, będziereturn false
, w przeciwnym razie będziereturn true
.Stosowanie:
bool isEqual = Compare<Employee>(Object1, Object2)
źródło
Aby rozwinąć odpowiedź @nawfal: s, używam tego do testowania obiektów różnych typów w moich testach jednostkowych w celu porównania równych nazw właściwości. W moim przypadku jednostka bazy danych i DTO.
Używane w ten sposób w moim teście;
źródło
czasami nie chcesz porównywać wszystkich właściwości publicznych i chcesz porównać tylko ich podzbiór, więc w tym przypadku możesz po prostu przenieść logikę, aby porównać żądaną listę właściwości z klasą abstrakcyjną
i użyj tej klasy abstrakcyjnej później do porównania obiektów
źródło
moje rozwiązanie zainspirowane powyższą odpowiedzią Arasa Alenina, w którym dodałem jeden poziom porównania obiektów i niestandardowy obiekt dla wyników porównania. Interesuje mnie również uzyskanie nazwy właściwości z nazwą obiektu:
Używanie następującej klasy do przechowywania wyników porównania
I przykładowy test jednostkowy:
źródło