【问题标题】:Is there a way to compare two objects of a different type in C#有没有办法在 C# 中比较两个不同类型的对象
【发布时间】:2017-04-04 14:36:23
【问题描述】:

我在这方面看到了一些类似的主题,但没有一个回答我的问题,我现在很挣扎,不得不问。

我有两个对象,一个名为 Customer,另一个是名为 customerDto 的数据传输对象。

客户:

public partial class Customer
{
    [DataMember] 
    public int Id { get;  set;}
    [DataMember] 
    public string Title { get;  set;}
    [DataMember] 
    public string FirstName { get;  set;}
    [DataMember] 
    public string Middle { get;  set;}
    [DataMember] 
    public string LastName { get;  set;}
    [DataMember] 
    public string Email { get;  set;}
    [DataMember] 
    public string HomePhone { get;  set;}
    [DataMember] 
    public string MobilePhone { get;  set;}
    [DataMember] 
    public string AddressLine1 { get;  set;}
    [DataMember] 
    public string AddressLine2 { get;  set;}
    [DataMember] 
    public string PostCode { get;  set;}
    [DataMember] 
    public DateTime? DateOfBirth { get;  set;}
    [DataMember][DatabaseGenerated(DatabaseGeneratedOption.Computed)] 
    public string FullName { get; private set;}
  }

public partial class Customer
{
    public virtual ICollection<DeliveryDetail> DeliveryDetails { get; set; }
    public virtual ICollection<Order> Order { get; set; }
}

CustomerDto:

public class CustomerDto : ICloneable
{
    public int Id { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PostCode { get; set; }
    public string Title { get; set; }
    public string Email { get; set; }
    public string HomePhone { get; set; }
    public string MobilePhone { get; set; }
    public DateTime? DateOfBirth { get; set; }
}

我需要比较它们共享的属性,但我不想编写多行 if 语句,因为那很混乱。有没有办法做到这一点?

我只需要看看他们共享的任何属性是否存在差异。如果有不同,那么我们可以改进和更新客户。

提前致谢。

【问题讨论】:

  • 为什么不创建一个子类,然后在那个元素上进行比较?
  • 您也可以使用反射来比较具有相同名称的字段,但我认为子类化或制作接口可能更好

标签: c# compare


【解决方案1】:

我认为您在这里寻找的是使用反射的 foreach 循环。

Customer customer; // assume its initialized
CustomerDto custDTO; 
var recordsAreDifferent = false;
foreach (var prop in custDTO.GetType().GetProperties())
{
  PropertyInfo customerProperty = customer.GetType().GetProperty(prop.name);
  if(customerProperty == null) {continue;}
 if(!prop.GetValue(custDTO, null).Equals(customerProperty.GetValue(customer,    null)) {
     recordsAreDifferent = true;
  }
}

【讨论】:

  • 作为更简洁的补充,我将使用Dictionary&lt;string, Tuple&lt;string, string&gt;&gt; differences,其中我将键作为字段,将两个字符串作为当前字符串并进行比较
【解决方案2】:

您可以考虑 Customer 类实现 IComparable 接口并实现 CompareTo(Object obj) 方法。

或者

实现IEquatable interface

【讨论】:

  • 除了他不想手动写出针对不同属性的所有检查。
  • 处理运行时错误,因为在反射期间发生了一些事情,这比编写(非常快速但冗长的)IComparable 实现要困难得多。
  • 这就是我说的你可以考虑 - 让他决定。
【解决方案3】:

您可以在使用反射的通用方法中执行此操作:

public static bool CompareMatchingProperties<TLeft,TRight>(TLeft lhs, TRight rhs) {
    var allLeft = typeof(TLeft).GetProperties().ToDictionary(p => p.Name);
    var allRight = typeof(TRight).GetProperties().ToDictionary(p => p.Name);
    foreach (var name in allLeft.Keys.Intersect(allRight.Keys)) {
        if (!object.Equals(allLeft[name].GetValue(lhs), allRight[name].GetValue(rhs))) {
            return false;
        }
    }
    return true;
}

这个想法是从两边的类型中获取所有公共属性(参见allLeftallRight字典)构造它们名称的交集(循环中的allLeft.Keys.Intersect(allRight.Keys)),从每个被比较的对象中获取属性值(allLeft[name].GetValue(lhs)allRight[name].GetValue(rhs))并使用 object.Equals 比较它们。

Demo.

使用这种方法要记住的一点是,比较两个没有任何共同属性的对象的结果将返回true。您可以通过要求至少匹配一对属性来解决此问题。

【讨论】:

  • 我还会考虑创建一个TryCompare...,它会返回一个解释性字典,说明不同之处......请参阅对其他答案的评论
【解决方案4】:

你可以这样写一个特定的方法:

    public bool UpdateCustomer(Customer customer, CustomerDto dto)
    {
        //Get properties from both objects
        System.Reflection.PropertyInfo[] customerProperties = customer.GetType().GetProperties();
        System.Reflection.PropertyInfo[] dtoProperties = dto.GetType().GetProperties();

        //Get properties that have the same name on both objects
        var propertiesToCompare = from customerProp in customerProperties 
                                  join dtoProp in dtoProperties 
                                  on customerProp.Name equals dtoProp.Name
                                  select customerProp;

        foreach (var property in propertiesToCompare)
        {
            if (property.GetValue(customer, null) != property.GetValue(dto, null))
                return true;
        }
        return false;
    }

您从两个对象中获取所有属性,然后检查它们共享的任何属性是否具有不同的值。如果是,则该方法返回 true。如果不是,则返回 false。

【讨论】:

    【解决方案5】:

    据我了解,CustomerDto 是 DB 的实体,Customer 是客户的合同。将 Customer 类型转换为 CustomerDto 并比较 CustomerDto 的两个对象呢?

    【讨论】:

      【解决方案6】:

      如果您需要比较 2 个对象并且您正在使用 C#,我认为执行此操作的一个好方法是使用运算符重载。要做到这一点,请考虑以下几点:

      • 所有运算符重载都是静态方法
      • 您有一元运算符和二元运算符。
      • 要重载比较器运算符(>、==、!=、>、=、" 也必须超载 "
      • 您必须在涉及的对象的某些类中声明它。

      sintaxis 是这样的。

          public static ReturnValue operator+(Object a, Object b)
          {
             // Comparison logic
             return value;
      
          }
      

      对于您的特定问题,您应该这样做:

      public static Boolean operator==(Customer cust, CustomerDto custDto)
      {
          //Here you code a for or foreach o whatever you want to compare
          //cust with custDto and return true is you found a difference or false
          //if there are no differences
      
          return booleanValue;
      }
      

      然后重载 != 运算符。要重用代码,您可以调用另一个比较器:

      public static Boolean operator!=(Customer cust, CustomerDto custDto)
          {  
              return !(cust == custDto);
          }
      

      因此,您可以在代码中检查一个 Customer 对象和一个 CustomerDto 对象之间是否存在差异,如下所示:

      if (customerObject == customerDtoObject)
      {
         //Whatever you want
      }
      

      希望这会对你有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多