【问题标题】:Comparing Nested object properties using C#使用 C# 比较嵌套对象的属性
【发布时间】:2010-07-19 17:44:34
【问题描述】:

我有一个方法可以比较两个对象并返回所有不同属性名称的列表。

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,但它没有告诉我 EmployeeAddress 中的哪个确切属性(在本例中为 Address1)已更改。如何调整此方法以获得类似 EmployeeAddress.Address1 的内容?

【问题讨论】:

    标签: c# reflection


    【解决方案1】:

    这是因为您使用的是!=,对于对象,它测试对象的身份而不是其值。关键是使用递归来生成属性的列表。这将达到你想要的深度......

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

    【讨论】:

    • 你能解释一下为什么你使用 Isprimitive,我正在尝试使用你的代码,当我关闭 isPrimitive 时,我总是在 !equal 部分出现不匹配错误。谢谢
    【解决方案2】:

    我可以推荐使用http://comparenetobjects.codeplex.com/ 这有可能比较嵌套对象、枚举、IList 等。 该项目免费且易于使用(只需 1 个 .cs 文件)。此外,还可以获取不同的值,添加要忽略的属性等。

    【讨论】:

      【解决方案3】:

      原则上,您需要在获得值后对要比较的两个对象使用您在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 属性,则为 Address.Name)。

      【讨论】:

        【解决方案4】:

        一点:您的方法没有考虑 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,您不会得到“不匹配”。

        关于引用的一些东西...

        无论如何,如果您想找到该对象的不同之处,您将不得不搜索该对象的不同之处。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-04-04
          • 2015-10-25
          • 2021-12-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-12
          相关资源
          最近更新 更多