Comparing Objects for Equality
What do we do when we want to do something which we haven’t done before? Basic instinct of a developer says that Google and this is what I did. And what was i trying? Write a unit test case to compare two objects for equality. By equality here, I mean similarity of data present int he objects.The objects I had to compare had sub-objects, properties as lists and the usual primitive data type properties. Unfortunately .Net doesn't have any API which compares object for equality.
After googling I saw an implementation in Codeplex which very much suited what I wanted, but the drawback being that it didn’t work if the objects had properties as Lists. I further enhanced this piece of code to work for properties which are sub-objects, lists and primitive data types. Here is the complete piece of code –
/// <summary>
/// This method compares two object for equality
/// </summary>
/// <typeparam name="T">Object type to be compared</typeparam>
/// <param name="expected">Expected object</param>
/// <param name="actual">Actual object</param>
/// <returns>boolean value indictaing the success ir failure of the comparison</returns>
public static bool CompareObjects<T>(T expected, T actual)
{
try
{
Type objectsType = typeof(T);
//When called recursive T will be of object type
if (objectsType.Name.ToString() == "Object")
objectsType = expected.GetType();
PropertyInfo[] properties = objectsType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty);
foreach (PropertyInfo pi in properties)
{
//Check if the object has a list
if (typeof(System.Collections.IList).IsAssignableFrom(pi.PropertyType))
{
System.Collections.IList listExpected = (System.Collections.IList)pi.GetValue(expected, null);
System.Collections.IList listActual = (System.Collections.IList)pi.GetValue(actual, null);
if (listExpected.Count != listActual.Count)
throw new Exception(String.Format("Objects do not match Expected Value {0} Actual Value {1}", listExpected.Count, listActual.Count));
for (int i = 0; i < listExpected.Count; i++)
CompareObjects(listExpected[i], listActual[i]);
}
//check if the property is a class,if class call CompareObjects recusively
else if (pi.PropertyType.IsClass && pi.PropertyType != typeof(string))
{
if (pi.GetIndexParameters().Length > 0)
CompareObjects(pi.GetValue(expected, new object[] { 0 }), pi.GetValue(actual, new object[] { 0 }));
else
CompareObjects(pi.GetValue(expected, null), pi.GetValue(actual, null));
}
object expectedValue = pi.GetIndexParameters().Length > 0 ? pi.GetValue(expected, new object[] { 0 }) : pi.GetValue(expected, null);
object actualValue = pi.GetIndexParameters().Length > 0 ? pi.GetValue(actual, new object[] { 0 }) : pi.GetValue(actual, null);
if (Convert.ToString(expectedValue) != Convert.ToString(actualValue))
throw new Exception(String.Format("Objects do not match Expected Value {0} Actual Value {1}", expectedValue, actualValue));
}
}
catch (Exception ex)
{
return false;
}
return true;
}
}


