Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I compare two objects' properties?

Tags:

c#

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.

like image 260
DenaliHardtail Avatar asked May 30 '13 17:05

DenaliHardtail


2 Answers

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.

like image 131
Reed Copsey Avatar answered Oct 03 '22 15:10

Reed Copsey


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.

like image 35
Sergey Kalinichenko Avatar answered Oct 03 '22 16:10

Sergey Kalinichenko