Use reflection to compare the properties of two objects

In an update to WilsonORWrapper, I added a method which takes two objects of the same type and compares the properties of each, returning a value reflecting the results of the comparison. Any value other than zero would indicate that at least one property on the objects are not equal.

This method may have interest to people who don’t use WilsonORWrapper, so here’s an extracted version of the code that does the comparison.

using System;
using System.Reflection;

public static class ObjectHelper<t>
{
	public static int Compare(T x, T y)
	{
		Type type = typeof(T);
		PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public);
		FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public);
		int compareValue = 0;

		foreach (PropertyInfo property in properties)
		{
			IComparable valx = property.GetValue(x, null) as IComparable;
			if (valx == null)
				continue;
			object valy = property.GetValue(y, null);
			compareValue = valx.CompareTo(valy);
			if (compareValue != 0)
				return compareValue;
		}
		foreach (FieldInfo field in fields)
		{
			IComparable valx = field.GetValue(x) as IComparable;
			if (valx == null)
				continue;
			object valy = field.GetValue(y);
			compareValue = valx.CompareTo(valy);
			if (compareValue != 0)
				return compareValue;
		}

		return compareValue;
	}
}

With that, if you had a Name class in your code that had two properties, First and Last, you could do something like this:

Name n1 = new Name();
n1.First = "Brian";
n1.Last = "DeMarzo";

Name n2 = new Name();
n2.First = "Brian";
n2.Last = "DeMarzo";

int result1 = ObjectHelper<name>.Compare(n1, n2);
// result1 == 0 because n1 and n2 have equal properties

n1.First = "Alyssa";
// change the first name, so n1 should no longer equal n2

int result2 = ObjectHelper</name><name>.Compare(n1, n2);
// result2 != 0 because n1 and n2 do not have equal properties

Code like this came in handy in my project where I use FileHelpers (see my blog entry from earlier today), where I was able to compare a class loaded from the database (using an O/R mapper) with a class loaded from a text file (using FileHelpers). Since the O/R mapper and FileHelpers used the same class, using this comparison method to determine if the objects were “equal” let me determine whether or not the data loaded from the database was different from the data in the text file.

Even though it used reflection, there wasn’t a huge performance hit, either. Sure beats writing manual comparison methods, which could take a while when you have a few dozen classes!

16 comments to Use reflection to compare the properties of two objects

  • I like your solution. I have actually thought about writing the same type of thing before, but I’m too lazy.

    You could just serialize out the objects to XML strings them do a simple compare on the strings. This does make the assumption the objects are marked as serializable.

  • Interesting idea with the XML serialization. It’s easy enough to tell if an object is serializable (i.e. examine attributes). I wonder which approach would perform better? The advantage of XML serialization is that we’re only comparing one value, though the serialization itself has overhead. Something to experiment with…

  • TC

    Thank you – very useful code. I intend to use similar code for unit testing when comparing expected and actual results for complex objects.

  • Kiran Kumar Singani

    Hi ,
    You have done great job, but one thing i found in your code is , there is not handling for internal objects which are not
    t derived from the IComparable. Missing functionality for collection objects.
    Regards,
    Kiran Kumar Singani

  • The code isn’t really intended to compare everything (such as collection comparison, which could be very cumbersome). Perhaps a more “generic” way would be to get each property value’s hash code and compare those — that would, at least, eliminate the IComparable requirement, though it wouldn’t be as precise.

  • Kwame

    Great article! We are facing a similar task which involves implementing an audit trail that requires us to to record what data was changed. Like Brain mentioned we considered serializing the objects and looking for changes but I think a direct object comparison is definitely more elegant. Thanks for sharing.

  • Swami

    If I have a property of type List, within the “Name” class, how could I compare values? Any idea?

  • Trevor

    It is obvious that nobody has actually tried your code.

    1) You have a lower case T in the ObjectHelper declaration (won’t compile)
    2) You are setting n2.Last before you instantiated the class (the first/last properties are mixed up).
    3) You wrote ObjectHelper.Compare(n1, n2) and its a generic type… it needs to be: ObjectHelper.Compare(n1, n2).

    4) It would be a lot more helpful if you demonstrated a base class that used such a technique such that every object that inherits from the class will automatically compare and equate by using all properties. Of course more than just Equals needs to be overridden, the operators too.
    5) I am not sure why you are comparing fields, does it make sense to have classes that are not equal based on non-public field values? Anyone interacting with the object would be confused.

  • Trevor

    I see this message box strips out the bracket characters…. perhaps that is what happened on step #3 which makes my post make no sense for line 3.

  • Rob

    Trevor, good point. The code is useless.

  • flotschie

    Hi, I also think about using your code for tracking changes in business objects.
    It would be great if the return value is not only a integer, but provides the information which property(ies) (string name) is(are) different and the two different values of each property in a way that you have the complete information where the two objects differ from each other. :-)

  • Rob

    Thx. Very helpfull creating my unit tests.

  • I created a class to do a deep compare of two objects on codeplex:

    http://comparenetobjects.codeplex.com/

  • Man you are super cool…i was able crack simple object..but wot about objects inside object..?
    do you think it is going to work..?

  • @Ashish — I would check out http://comparenetobjects.codeplex.com/ — it seems to do a lot!

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>