mercredi 15 avril 2020

Compare two Complex Objects in c#

I am trying to compare two objects and want to identify the difference in objects.

It works fine if I don't use List. But when I use List, Although the List in both objects are equal, it says it's not equal and go to check for List difference. Since, for now, I don't have the condition for list comparison it crashes and gives me this exception System.Reflection.TargetParameterCountException: 'Parameter count mismatch.'

I have taken help from one of the stackoverflow post from here. Here is my code which I have written so far.

public class Program
{
    public static void Main()
    {
        Employee emp1 = OldEmployee();

        Employee emp2 = NewEmployee();

        var list = GetDifferingProperties(emp1, emp2);

        foreach (var s in list)
            Console.WriteLine(s);
    }

    public static IList<string> GetDifferingProperties(object source, object target)
    {
        var sourceType = source.GetType();
        var sourceProperties = sourceType.GetProperties();
        var targetType = target.GetType();
        var targetProperties = targetType.GetProperties();

        var result = new List<string>();

        foreach (var property in
            (from s in sourceProperties
             from t in targetProperties
             where s.Name == t.Name &&
             s.PropertyType == t.PropertyType &&
             !Equals(s.GetValue(source, null), t.GetValue(target, null))
             select new { Source = s, Target = t }))
        {
            // it's up to you to decide how primitive is primitive enough
            if (IsPrimitive(property.Source.PropertyType))
            {
                result.Add(property.Source.Name);
            }
            else
            {
                foreach (var subProperty in GetDifferingProperties(
                    property.Source.GetValue(source, null),
                    property.Target.GetValue(target, null)))
                {
                    result.Add(property.Source.Name);
                }
            }
        }

        return result;
    }

    private static bool IsPrimitive(Type type)
    {
        return type == typeof(string)
            || type == typeof(int) || type == typeof(int?)
            || type == typeof(double) || type == typeof(double?)
            || type == typeof(bool) || type == typeof(bool?)
            || type == typeof(Guid) || type == typeof(Guid?)
            || type == typeof(DateTime) || type == typeof(DateTime?);
    }

    public static string GetPropertyDisplayName(PropertyInfo pi)
    {
        var dp = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault();
        return dp != null ? dp.DisplayName : pi.Name;
    }

    private static Employee NewEmployee()
    {
        var contactDetail = new ContactDetails();
        contactDetail.ContactNumber = "123456789";

        var employeeAddress = new Address();
        employeeAddress.AddressLine1 = "Microsoft Corporation";
        employeeAddress.AddressLine2 = "One Microsoft Way";
        employeeAddress.City = "Redmond";
        employeeAddress.State = "WA";
        employeeAddress.Zip = "98052-6399";
        employeeAddress.ContactDetails = new List<ContactDetails>() { contactDetail };

        var employee = new Employee();
        employee.FirstName = "Bill";
        employee.LastName = "Gates";
        employee.MiddleName = "Middle Name";
        employee.IsActive = true;
        employee.JoinDate = new DateTime(2015, 10, 15);
        employee.ReleaseDate = new DateTime(2015, 10, 15);
        employee.EmployeeAddress = employeeAddress;
        return employee;
    }

    private static Employee OldEmployee()
    {
        var contactDetail = new ContactDetails();
        contactDetail.ContactNumber = "123456789";

        var employeeAddress = new Address();
        employeeAddress.AddressLine1 = "Microsoft Corporation";
        employeeAddress.AddressLine2 = "One Microsoft Way";
        employeeAddress.City = "Redmond";
        employeeAddress.State = "WA";
        employeeAddress.Zip = "98052-6399";
        employeeAddress.ContactDetails = new List<ContactDetails>() { contactDetail };

        var employee = new Employee();
        employee.FirstName = "Bill";
        employee.LastName = "Gates";
        employee.MiddleName = "Middle Name";
        employee.IsActive = true;
        employee.JoinDate = new DateTime(2015, 10, 15);
        employee.ReleaseDate = new DateTime(2015, 10, 15);
        employee.EmployeeAddress = employeeAddress;
        return employee;
    }
}

public class ContactDetails
{
    public string ContactNumber { get; set; }
}

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 bool IsActive { get; set; }
    public List<ContactDetails> ContactDetails { get; set; }
}

public class Employee
{
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
    public bool IsActive { get; set; }
    public DateTime JoinDate { get; set; }
    public DateTime? ReleaseDate { get; set; }
    public Address EmployeeAddress { get; set; }
}

If I comment out the line employeeAddress.ContactDetails = new List<ContactDetails>() { contactDetail }; from oldEmployee and newEmployee, it works fine, and if there is any difference in EmployeeAddress it identifies it, and if there isn't any difference it doesn't. But if I uncomment this line employeeAddress.ContactDetails = new List<ContactDetails>() { contactDetail }; it takes out EmployeeAddress as it has difference, although it doesn't. Can some one please suggest what I am missing, I have spent a lot of time to identify the issue.

My Target to Achieve is, to make a list of properties that has a difference in Employee Object, for Example,

  1. If FirstName in Employee has difference result list should contain only FirstName
  2. If FirstName in Employee and AddressLine1 in EmployeeAddress has difference result list should contain (FirstName, EmployeeAddress)
  3. Similarly, If FirstName in Employee and ContactNumber in ContactDetails which is a List in Address has difference result list should contain (FirstName, EmployeeAddress), In this case result list still contains EmployeeAddress because ContactNumber is in EmployeeAddress which is in Employee, So our main focus is to get parent Properties that has difference is source and target object.

Point 1 and Point 2 are working as Expected. Iff I comment out employeeAddress.ContactDetails = new List<ContactDetails>() { contactDetail }; because it causing exception and also it coming with change although it doesn't have any change in source and target.

Any help would be highly appreciated, or you can suggest me some other way of implementation too.





Aucun commentaire:

Enregistrer un commentaire