5

How do I compare the properties of two objects to determine if any properties have changed? I have a Patient object with a series of properties. I have a second object, UpdatedPatient, that may have different values. Currently, I'm using the following for each property:

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

After all the properties are checked, if the PatientChanged flag is true, the patient is updated. Yes, it works but I'm questioning if this if the most efficient solution.

Lorenzo B
  • 33,216
  • 24
  • 116
  • 190
DenaliHardtail
  • 27,362
  • 56
  • 154
  • 233
  • You could use this example from a similar question. http://stackoverflow.com/questions/957783/loop-through-an-objects-properties-in-c-sharp – Bearcat9425 May 30 '13 at 17:17
  • 2
    What's the context? For example, many frameworks and patterns would have you implement `INotifyPropertyChanged` and subscribe to events if you wish to be informed of data changes. It doesn't eliminate your coding problem, of course, but depending upon what you're doing, perhaps you should explore it. – Anthony Pegram May 30 '13 at 17:18

3 Answers3

9

Yes, it works but I'm questioning if this if the most efficient solution.

This is likely the most efficient solution in terms of runtime efficiency.

After all the properties are checked, if the PatientChanged flag is true, the patient is updated

You could speed this up if you short curcuit - as soon as any property is checked and the PatientChanged is true, you know you need to update, so you could skip the other checks.

You could, of course, use Reflection to write a method to do this check for you. However, this would be far less efficient in terms of performance, but it might eliminate having to write these checks for all of your types, which could improve developer efficiency.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
5

I'm questioning if this if the most efficient solution.

The answer depends on the way in which you are measuring the efficiency.

  • In terms of CPU cycles, this is the most efficient way
  • In terms of maintenance efforts, methods based on reflection would prove more efficient.

You may want to built a hybrid LINQ/Reflection solution to get acceptable efficiency and keep maintainability in place: use reflection to get all your properties that you need to compare, build a LINQ expression tree that compares them one by one, compile it as a lambda, and use the resultant functor for CPU-efficient comparisons.

Here is a sample implementation of the hybrid approach:

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();
}

With this method in hand, you can perform comparisons like this:

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));

Here is a demo of this approach on ideone.

Note that this implementation is rather simplistic. It uses == for all attributes, rather than going for Equals where appropriate. You can expand upon it by making line 7 more sophisticated.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
0

If you made exPt a struct, instead of a class, then its .Equals method would compare each of the fields, rather than a reference comparison.

Deeko
  • 1,514
  • 9
  • 29
  • 1
    That is true, but you usually should not use the default `Equals()` of `struct`s, because it is quite slow (because it uses reflection). – svick May 30 '13 at 17:30
  • True. It's quick and simple to code, but not necessarily to execute. – Deeko May 30 '13 at 17:45