2013-05-30 13 views
5

Jak porównać właściwości dwóch obiektów, aby określić, czy zmieniły się jakieś właściwości? Mam obiekt Patient z szeregiem właściwości. Mam drugi obiekt, UpdatedPatient, który może mieć różne wartości. Obecnie używam następujących dla każdej nieruchomości:Jak porównać właściwości dwóch obiektów?

if (exPt.Id!= pt.Id) 
{ 
    exPt.Id = pt.Id; 
    PatientChanged = true; 
} 

Po sprawdzane są wszystkie właściwości, jeśli flaga PatientChanged jest true, pacjent jest aktualizowana. Tak, działa, ale pytam, czy to jest najbardziej wydajne rozwiązanie.

+0

Możesz użyć tego przykładu z podobnego pytania. http://stackoverflow.com/questions/957783/loop-through-an-objects-properties-in-c-sharp – Bearcat9425

+2

Jaki jest kontekst? Na przykład wiele frameworków i wzorców implementowałoby 'INotifyPropertyChanged' i subskrybuje zdarzenia, jeśli chcesz być informowany o zmianach danych. Oczywiście nie eliminuje to twojego problemu z kodowaniem, ale w zależności od tego, co robisz, być może powinieneś to zbadać. –

Odpowiedz

9

Tak, działa, ale pytam, czy to jest najbardziej wydajne rozwiązanie.

Jest to prawdopodobnie najbardziej wydajne rozwiązanie pod względem wydajności podczas pracy.

Po sprawdzane są wszystkie właściwości, jeśli PatientChanged flaga jest prawdą, pacjent jest aktualizowana

Można to przyspieszyć, jeśli krótki curcuit - jak najszybciej wszelkich nieruchomości jest sprawdzana i PatientChanged jest true, wiesz, że musisz zaktualizować, więc możesz pominąć inne kontrole.

Można oczywiście użyć metody Reflection, aby napisać metodę wykonania tego sprawdzenia. Byłoby to jednak o wiele mniej wydajne pod względem wydajności, ale może wyeliminować konieczność pisania tych kontroli dla wszystkich typów, co może poprawić wydajność programisty.

+0

+1 za porady dotyczące zwarć –

5

Pytam, czy to jest najbardziej wydajne rozwiązanie.

Odpowiedź zależy od sposobu mierzenia efektywności.

  • Pod względem cykli procesora, jest to najbardziej efektywny sposób
  • Pod względem działań konserwacyjnych, metody oparte na refleksji by okazać się bardziej efektywne.

Być może zechcesz zbudować hybrydowe rozwiązanie LINQ/Reflection, aby uzyskać akceptowalną wydajność i utrzymać konserwację na miejscu: użyj refleksji, aby uzyskać wszystkie właściwości, które musisz porównać, zbuduj drzewo wyrażeń LINQ, które porównuje je przez jeden, skompiluj go jako lambda i użyj wynikowego funktora do porównań wydajnych CPU.

Oto próbka implementacja podejścia hybrydowego:

public static Func<T,T,bool> MakeComparator<T>() { 
    var lhs = Expression.Parameter(typeof (T)); 
    var rhs = Expression.Parameter(typeof (T)); 
    var allPropChecks = typeof(T) 
     .GetProperties() 
     .Where(p => p.CanRead && p.GetIndexParameters().Length == 0) 
     .Select(p => Expression.Equal(Expression.Property(lhs, p), Expression.Property(rhs, p))) 
     .ToList(); 
    Expression compare; 
    if (allPropChecks.Count == 0) { 
     return (a,b) => true; // Objects with no properties are the same 
    } else { 
     compare = allPropChecks[0]; 
     compare = allPropChecks 
      .Skip(1) 
      .Aggregate(compare, Expression.AndAlso); 
    } 
    return (Func<T, T, bool>)Expression.Lambda(compare, new[] { lhs, rhs }).Compile(); 
} 

Dzięki tej metodzie w ręku, można wykonać porównań tak:

class Point3D { 
    public int X { get; set; } 
    public int Y { get; set; } 
    public int Z { get; set; } 
} 
... 
// Construct sample objects 
var p1 = new Point3D { X = 1, Y = 2, Z = 3}; 
var p2 = new Point3D { X = 1, Y = 2, Z = 3 }; 
var p3 = new Point3D { X = 1, Y = 3, Z = 1 }; 
// Get a comparator 
var cmp = MakeComparator<Point3D>(); 
// Use the comparator to compare objects to each other 
Console.WriteLine(cmp(p1, p2)); 
Console.WriteLine(cmp(p2, p3)); 

Oto demo of this approach on ideone.

Należy zauważyć, że ta implementacja jest raczej uproszczona. Używa == dla wszystkich atrybutów, zamiast w razie potrzeby podążać za Equals.Możesz go rozwinąć, tworząc linię 7 bardziej wyrafinowaną.

+0

+1 wiele rzeczy tutaj;) –

0

Jeśli stworzysz exPt struct, zamiast klasy, to jego metoda .Equals porównałaby każde z pól, zamiast porównywania referencyjnego.

+1

To prawda, ale zwykle nie powinieneś używać domyślnego 'Equals()' 'struct's, ponieważ jest dość powolny (ponieważ używa odbicie). – svick

+0

Prawda. Kodowanie jest szybkie i proste, ale niekoniecznie konieczne do wykonania. – Deeko

Powiązane problemy