Sometimes you end up with two instances of the same class and you need to know what changed between them. This cropped up for me when I was auditing edits to a model object: I had oldObj and newObj and I wanted a list of the property names whose values differed.
You could write a custom comparison for every class, but if you want something generic that works for any type, reflection is the obvious tool. The method below handles:
- primitive properties (
int,string,bool,decimal, etc.) - reference properties where the two objects point to the same instance (it does not do deep comparison)
- a sanity check that both arguments are non-
nulland of the same type
public List<string> GetChangedProperties(object obj1, object obj2)
{
List<string> result = new List<string>();
if(obj1 == null || obj2 == null )
// just return empty result
return result;
if (obj1.GetType() != obj2.GetType())
throw new InvalidOperationException("Two objects should be from the same type");
Type objectType = obj1.GetType();
// check if the objects are primitive types
if (objectType.IsPrimitive || objectType == typeof(Decimal) || objectType == typeof(String) )
{
// here we shouldn't get properties because its just primitive :)
if (!object.Equals(obj1, obj2))
result.Add("Value");
return result;
}
var properties = objectType.GetProperties();
foreach (var property in properties)
{
if (!object.Equals(property.GetValue(obj1), property.GetValue(obj2)))
{
result.Add(property.Name);
}
}
return result;
}
Call it with your two instances and you’ll get a list of strings containing the names of every property whose value didn’t match. If the objects themselves are primitives (e.g. you pass two string objects) the method treats the entire value as a single comparison and returns a single entry named "Value" when they differ.
Note: the hash-like comparison above is shallow. If a property is a custom class, the method just compares the references. You’ll need to extend it if you want recursive comparison. Also, the method only inspects properties – if you use public fields instead you’ll need to call
GetFields().
Reflection isn’t the only way to do this, but it’s perfectly reasonable when you don’t know the concrete type at compile time. For cases where performance is critical you could generate expressions or use a library such as FastMember.
The original Stack Overflow answer that inspired this post was written on 03-Sep-2015 and can be found here:
https://stackoverflow.com/questions/31858359/compare-2-object-of-the-same-class/31858604#31858604
Happy diffing!