Сравнение свойств вложенных объектов с использованием C # - PullRequest
4 голосов
/ 24 марта 2010

У меня есть метод, который сравнивает два объекта и возвращает список всех имен свойств, которые отличаются.

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 properties = (from s in sourceProperties
                      from t in targetProperties
                      where s.Name == t.Name &&
                            s.PropertyType == t.PropertyType &&
                            s.GetValue(source,null) != t.GetValue(target,null)
                      select s.Name).ToList();
    return properties;
}

Например, если у меня есть два класса следующим образом:

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; }
        }

Я пытаюсь сравнить следующие два экземпляра сотрудника:

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;

Поэтому, когда я передаю эти два объекта сотрудника моему методу GetDifferingProperties, в настоящее время он возвращает FirstName и EmployeeAddress, но он не сообщает мне, какое именно свойство (в данном случае это Address1) в EmployeeAddress изменилось. Как я могу настроить этот метод, чтобы получить что-то вроде EmployeeAddress.Address1?

Ответы [ 4 ]

3 голосов
/ 24 марта 2010

Это потому, что вы используете !=, который для объектов проверяет идентичность объекта, а не его значение. Ключ заключается в том, чтобы использовать рекурсию для генерации списка свойств свойств. Это будет так глубоко, как вы хотите ...

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 + "." + subProperty);
      }
    }
  }

  return result;
}

private static bool IsPrimitive(Type type)
{
  return type == typeof(string) || type == typeof(int);
}
2 голосов
/ 19 июля 2010

Я могу рекомендовать использовать http://comparenetobjects.codeplex.com/ Это позволяет сравнивать вложенные объекты, перечисления, ILists и т. Д. Проект бесплатный и простой в использовании (файл Just 1 .cs). Более того, можно получить разные значения, добавить свойства, которые нужно игнорировать и т. Д.

1 голос
/ 24 марта 2010

В принципе, вам нужно использовать технику, которую вы реализовали в GetDifferingProperties, для двух объектов, которые вы хотите сравнить после получения их значений (используя GetValue в запросе). Вероятно, самая простая реализация - сделать метод рекурсивным:

public static IEnumerable<string> GetDifferingProperties
    (object source, object target) {

  // Terminate recursion - equal objects don't have any differing properties
  if (source == target) return new List<string>();

  // Compare properties of two objects that are not equal
  var sourceProperties = source.GetType().GetProperties();
  var targetProperties = target.GetType().GetProperties();
  return
    from s in sourceProperties
    from t in targetProperties
    where s.Name == t.Name && s.PropertyType == t.PropertyType 
    let sVal = s.GetValue(source, null)
    let tVal = t.GetValue(target, null)

    // Instead of comparing the objects directly using '==', we run
    // the method recursively. If the two objects are equal, it returns
    // empty list immediately, otherwise it generates multiple properties
    from name in GetDifferingProperties(sVal, tVal)
    select name;
}

Если вы хотите использовать это на практике, вы, вероятно, захотите отслеживать, как добраться до свойства (этот код дает вам просто список имен свойств без информации об объекте, который их содержит). Вы можете изменить последнюю строку с select name на select s.Name + "." + name, что даст вам более полное имя (например, Address.Name, если отличающееся свойство является свойством Name элемента Address).

0 голосов
/ 24 марта 2010

Одно замечание: Ваш метод не учитывает фактические различия в свойствах EmployeeAddress. Проверьте это и посмотрите.

        emp2Address.AddressLine1 = emp1Address.AddressLine1;// "Gates Foundation";
        emp2Address.AddressLine2 = emp1Address.AddressLine2;// "One Microsoft Way";
        emp2Address.City = emp1Address.City;// "Redmond";
        emp2Address.State = emp1Address.State;// "WA";
        emp2Address.Zip = emp1Address.Zip;// "98052-6399";

Программа по-прежнему будет возвращать EmployeeAddress как несоответствующее свойство. Однако, если вы просто установите emp2.EmployeeAddress = emp1Address, вы не получите «несоответствие».

Что-то в ссылках ...

В любом случае, если вы хотите найти что отличается от этого объекта, вам придется найти , что отличается от этого объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...