如何比较两个对象-在比较中排除特定属性

本文关键字:比较 排除 属性 两个 何比较 对象 | 更新日期: 2023-09-27 18:26:00

我有一个案例,我想比较c#中的两个对象。此外,在比较时,我可以选择排除特定的属性。有人能提出更好的方法吗。类将如下所示

public class Address
{
    public string AddressID { get; set; }
    public int AddressStagingID { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string County { get; set; }
    public string Postcode { get; set; }
    public string Country { get; set; }
    public bool PreferredAddress { get; set; }
    public int? DBID { get; set; }
    public Enum AddressStatus Status { get; set; }
}

我需要一个类似的功能

private bool IsAddressModified(Address currentAddress,Address existingAddress)
    {
    }

如何比较两个对象-在比较中排除特定属性

Compare NET对象拥有您所需要的一切!

按表达式忽略

CompareLogic compare = new CompareLogic();
compare.Config.IgnoreProperty<Person>(x => x.Name);

按ClassName.MemberName忽略

CompareLogic compare = new CompareLogic();
compare.Config.MembersToIgnore.Add("Person.Name");

忽略具有名称的所有成员

CompareLogic compare = new CompareLogic();
compare.Config.MembersToIgnore.Add("UpdateDate");

使用通配符忽略

CompareLogic compare = new CompareLogic();
compare.Config.MembersToIgnore.Add("*Id");

使用属性忽略

[AttributeUsage(AttributeTargets.Property)]
public sealed class CompareIgnoreAttribute : Attribute
{
}
public class Shipment
{
    public long IdentCode { get; set; }
    public String Customer { get; set; }
    
    [CompareIgnore]
    public DateTime InsertDate { get; set; }
}
CompareLogic compare = new CompareLogic();
compare.Config.AttributesToIgnore.Add(typeof(CompareIgnoreAttribute));

仅比较属性和属性

public class Movie 
{
    [Compare]
    public string Name { get; set; }
    public decimal PaymentForTomCruise { get; set; }
}
CompareLogic compare = new CompareLogic();
compare.Config.RequiredAttributesToCompare.Add(typeof(CompareAttribute));

我试图使用表达式树开发一个不同的解决方案,在我看来,这是更灵活的

public class Test
{
    public static void Main()
    {
       Address a1 = new Address();
       a1.AddressID = "100";
    
       Address a2 = new Address();
       a2.AddressID = "200";
       Console.WriteLine(IsAddressModified(a1,a2,a=>a.AddressID));
    }
   public static bool IsAddressModified(Address a1,Address a2,params Expression<Func<Address,Object>>[] props)
   {
       if(props == null)
          return a1.Equals(a2);
        
      foreach(Expression<Func<Address,object>> memberExpression in props)
      {
          MemberExpression property = memberExpression.Body as MemberExpression;
          if(property != null)
          {
              foreach(PropertyInfo pi in typeof(Address).GetProperties())
              {
                // exclude all properties we passed in
                  if(!pi.Name.Equals(property.Member.Name))
                  {
                    
                      var valueA1 = pi.GetValue(a1);
                      var valueA2 = pi.GetValue(a2);
                      if(valueA1 != null && valueA2 != null)
                          if(!valueA1.Equals(valueA2))
                              return true;
                  }
              }
          }
      }
    
      return false;
  }
}

那么代码是什么呢?

  1. 您可以将一个"属性"数组传递给方法IsAddressModified。比较时将排除这些属性
  2. 从表达式中,我提取一个MemberExpression来获得每个属性的名称
  3. 我遍历类型Address的所有属性,并检查它是否是要排除的一个属性
  4. 最后但同样重要的是,我比较了属性值

为什么这么"复杂"

使用此解决方案,您可以向函数中传递任意多的属性,并且在编译过程中完全是类型安全的。

在Main中,你可以看到我是如何调用这个函数的。即使由于a1a2AddressID不同,函数也会返回false,因为您排除了AddressID

完整的可编译示例可以在这里找到

反射如何:

  private bool IsAddressModified(Address currentAddress, Address existingAddress)
        {
            foreach (PropertyInfo pi in currentAddress.GetType().GetProperties())
            {
                //To exclude properties use condition
                if (pi.Name != "City") { 
                object currentElement = typeof(Address).GetProperty(pi.Name).GetValue(currentAddress,null);
                object existingElement = typeof(Address).GetProperty(pi.Name).GetValue(existingAddress,null);
                if (!currentElement.Equals(existingElement))
                { return false; }
                }
                return true;    
            }
        }

如果您正在寻找非常简单的东西,请使用反射。但是,如果您需要高级内容,请使用CompareObjects。这是Nuget。此库还可以提供有关更改的详细报告。这意味着你可以使用它来记录等

这是来自该网站的示例代码。

//This is the comparison class
CompareLogic compareLogic = new CompareLogic();
//Create a couple objects to compare
Person person1 = new Person();
person1.DateCreated = DateTime.Now;
person1.Name = "Greg";
Person person2 = new Person();
person2.Name = "John";
person2.DateCreated = person1.DateCreated;
ComparisonResult result = compareLogic.Compare(person1, person2);
//These will be different, write out the differences
if (!result.AreEqual)
   Console.WriteLine(result.DifferencesString);

暴力?

private bool IsAddressModified(Address a, Address b)
{
    return a.Address1 != b.Address1 || a.Address2 != b.Address2 
       || a.City != b.City || a.PostCode != b.PostCode;
    // etc. for all the properties that are considered as modified
}