Comparing Object properties using reflection

I have two classes Address and Employee as follows:

 public class Address
{
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

   public class Employee
    {
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public Address EmployeeAddress { get; set; }
    }

I have two employee instances as follows:

    var emp1Address = new Address();
    emp1Address.AddressLine1 = "Microsoft Corporation";
    emp1Address.AddressLine2 = "One Microsoft Way";
    emp1Address.City = "Redmond";
    emp1Address.State = "WA";
    emp1Address.Zip = "98052-6399";

    var emp1 = new Employee();
    emp1.FirstName = "Bill";
    emp1.LastName = "Gates";
    emp1.EmployeeAddress = emp1Address;


    var emp2Address = new Address();
    emp2Address.AddressLine1 = "Gates Foundation";
    emp2Address.AddressLine2 = "One Microsoft Way";
    emp2Address.City = "Redmond";
    emp2Address.State = "WA";
    emp2Address.Zip = "98052-6399";

    var emp2 = new Employee();
    emp2.FirstName = "Melinda";
    emp2.LastName = "Gates";
    emp2.EmployeeAddress = emp2Address;

Now how can I write a method which compares these two employees and returns the list of properties which have different values. So in this example I would like the result to be FirstName and Address.AddressLine1 .

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Like LBushskin said, you do not have to do this. This is not the fastest way! Buy if you want, try this:

    public static List<PropertyInfo> GetDifferences(Employee test1, Employee test2)
    {
        List<PropertyInfo> differences = new List<PropertyInfo>();
        foreach (PropertyInfo property in test1.GetType().GetProperties())
        {
            object value1 = property.GetValue(test1, null);
            object value2 = property.GetValue(test2, null);
            if (!value1.Equals(value2))
            {
                differences.Add(property);
            }
        }
        return differences;
    }

Method 2

You don’t necessarily need reflection to perform the comparison. You can write a comparer class that takes two instances of Employee or Address, and compares each field that should match. For any that don’t match, you can add a string (or PropertyInfo) element to some list to return to the caller.

Whether you return a PropertyInfo, MemberInfo, or just a string depends on what the caller needs to do with the result. If you actually need to visit the fields that contain differences, the PropertyInfo/MemberInfo may be better – but to just report the differences a string is probaby sufficient.

The main value of reflection would be to write a general purpose object comparer that could take two instances of any kind of object and compare their public fields and properties. This helps avoid writing repetetive comparison code over and over – but that doesn’t seem like the case you’re in.

Method 3

Here is a generic and recursive solution based on Oskar Kjellin’s awnser.

I have posted this code as gist as well, so you can check the latest version or star/clone/fork it 🙂

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

protected List<KeyValuePair<Type, PropertyInfo>> RecrusiveReflectionCompare<T>(T first, T second)
        where T : class
    {
        var differences = new List<KeyValuePair<Type, PropertyInfo>>();

        var parentType = first.GetType();

        void CompareObject(object obj1, object obj2, PropertyInfo info)
        {
            if (!obj1.Equals(obj2))
            {
                differences.Add(new KeyValuePair<Type, PropertyInfo>(parentType, info));
            }
        }

        foreach (PropertyInfo property in parentType.GetProperties())
        {
            object value1 = property.GetValue(first, null);
            object value2 = property.GetValue(second, null);

            if (property.PropertyType == typeof(string))
            {
                if (string.IsNullOrEmpty(value1 as string) != string.IsNullOrEmpty(value2 as string))
                {
                    CompareObject(value1, value2, property);
                }
            }
            else if (property.PropertyType.IsPrimitive)
            {
                CompareObject(value1, value2, property);
            }
            else
            {
                if (value1 == null && value2 == null)
                {
                    continue;
                }

                differences.Concat(RecrusiveReflectionCompare(value1, value2));
            }
        }
        return differences;
    }

Method 4

public IEnumerable<PropertyInfo> GetNotEqualsProperties(Employee emp1, Employee emp2)
{
    Type employeeType = typeof (Employee);
    var properies = employeeType.GetProperties();
    foreach (var property in properies)
        if(!property.GetValue(emp1, null).Equals(property.GetValue(emp2, null))) //TODO: check for null
            yield return property;
}

And for complex properties you have to override Equals method

public class Address
{
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }

    public override bool Equals(object obj)
    {
        if (obj as Address == null)
            return false;
        return ((Address) obj).AddressLine1.Equals(AddressLine1);
    }
}

Method 5

No need for reflection. Of course, this example is returning a string with the property names…if you need the actual PropertyInfo object, things would get a little more difficult, but not by much.

public static IEnumerable<string> DiffEmployees
    (Employee one, Employee two)
{
    if(one.FirstName != two.FirstName)
        yield return "FirstName";
    if(one.LastName != two.LastName)
        yield return "LastName";
    if(one.Address.AddressLine1 != two.Address.AddressLine1)
        yield return "Address.AddressLine1";

    // And so on.
}


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x