Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing two objects' properties simply in c#

I have a class with lots of properties. A shallow copy is enough to fully replicate the object.

I need to compare an object just to check if it contains exactly the same values as another.

My ideas:

The first and most obvious solution is just to create a huge method block that compares each property, one after the other.

The second would be to serialize each object and hash the file or do some sort of md5 checksum on it. (Would this actually work?)

The third is to do some sort of reflection on the object, which would automate the first option, but create an added level of complexity.

Speed isn't really an issue.

I'm interested to hear thoughts, or any other methods I am missing to do such a thing.

Edit: Thanks all. My solution (Modified to now be recursive on generic items):

public static bool IsSame<T>(T objA, T objB)
{
    var type = typeof(T);
    var properties = type.GetProperties();
    foreach (var pi in properties.Where(a => a.CanRead))
    {
        if (pi.Name == "Item")
        {
            var piCount = properties.FirstOrDefault(a => a.Name == "Count");
            int count = -1;
            if (piCount != null && piCount.PropertyType == typeof(System.Int32))
                count = (int)piCount.GetValue(objA, null);
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    dynamic child1 = pi.GetValue(objA, new object[] { i });
                    dynamic child2 = pi.GetValue(objB, new object[] { i });
                    return IsSame(child1, child2);
                }
            }
        }
        else
        {
            var val1 = type.GetProperty(pi.Name).GetValue(objA, null);
            var val2 = type.GetProperty(pi.Name).GetValue(objB, null);
            if (val1 != val2 && (val1 == null || !val1.Equals(val2)))
                return false;
        }
    }
    return true;
}
like image 705
maxp Avatar asked Jan 19 '12 15:01

maxp


1 Answers

Most serializers are designed to ensure that data retains its integrity during serialization and deserialization, not to produce a consistent serialized format. I would avoid using serialization for this purpose.

You may consider implementing IEquatable, to have each instance capable of comparing itself with instances of the same type. Or a class do do the comparisons for you that implements IEqualityComparer. How they do this comparison may be the 'big method' that compares properties one after the other, or uses reflection.

Reflection can be a fairly quick and simple way to achieve your goal but can cause problems down the line (for example if someone adds a property to your type that should not be included for comparing equality), but obviously the converse is also true (someone adds a property that should be checked for equality, but the equality comparison isn't updated). Which approach you use should generally be decided by how comfortable the team is with each approach in tandem with the context in which the class will be used.

In your case I'd probably recommend using the reflection based approach since you wish to check the result of a shallow clone operation, so all properties should be equal.

As an aside, I'd recommend using the MemberwiseClone method to create the clone, which would lessen the need for such stringent tests.

like image 142
Rich O'Kelly Avatar answered Oct 23 '22 01:10

Rich O'Kelly