【问题标题】:Determining equality for unknown types确定未知类型的相等性
【发布时间】:2016-08-23 06:56:31
【问题描述】:

我需要检查给定的实例是否与集合匹配(两者都是未知类型)。

看看

void Main()
{
    // Employee "John" Object got from Service Layer #1
    Object obj1 = Client1.GetObject("John");

    // Employee "John" Object got from Service Layer #2
    Object obj2 = Client2.GetObject("John");

    bool flag = CheckEquality(obj1, obj2); // Both objects are Unknown Type
}

等式检查方法:

public bool CheckEquality(object obj1, object obj2)
{
    // Solution for Determining equality for unknown types
}

例如 - 考虑以下代码:(仅用于理解目的)

场景 #1

public class EmpPerson
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
}

obj1 持有实例new EmpPerson() { ID = 1, Name = "John", Address = "Los Angeles" };

obj2 持有实例new EmpPerson() { ID = 1, Name = "John", Address = "Los Angeles" };

场景 #2

obj1 持有值"John Smith"

obj2 持有值"John Smith"

场景#3

obj1 持有值"John Smith"

obj2 持有实例new EmpPerson() { ID = 1, Name = "John", Address = "Los Angeles" };

场景#4

obj1 持有值new UnknownTypeA()

obj2 持有值new UnknownTypeX()

我需要检查两个对象是否相同。

请帮助我。如何检查未知类型的相等性。

【问题讨论】:

  • 那么可能涉及到哪些其他类型?根据 cmets 之前在另一个问题中的说法,该类型是否可能具有任何“隐藏”状态,而不是由字段公开?它可以包含一个集合吗?它是否可以包含Random 属性,作为隐藏其状态的类型的示例?它可以包含循环引用吗?这通常是不可能的,但如果你限制所涉及的类型,你可以通过反射来做到这一点。 (你确实需要小心循环引用......)
  • 在场景 #2 中,obj1obj2 只是字符串,还是它们也是 EmpPerson 类型但您只知道名称?
  • 您确实需要说明如何检查是否相等。如果obj1 只包含名称,而obj2 包含相同的名称以及ID 和地址,那么它们是否相等?
  • “它包含随机属性”是指类型可以包含System.Random 类型的属性吗?如果是这样,游戏就结束了 - 你真的无法比较 Random 实例的相等性。
  • 如果您给出场景的预期结果也会有所帮助 - 在场景 4 中,如果 obj1obj2 具有相同的属性,但它们属于不同的类型,应该这样算不算相等?

标签: c# .net observablecollection iequalitycomparer data-compression


【解决方案1】:

您可以查看Compare-Net-Objects deep equals library,它可用于通过反射对对象进行深度比较。

【讨论】:

    【解决方案2】:

    此代码将在不使用递归对象的情况下按类型和公共字段列表进行比较。可以通过添加递归和属性来改进它。但当然,这并不是所有情况下的解决方案。

    bool AreEquals(object a, object b)
    {
      if (a == null && b == null) return true;
      if (a == null || b == null) return false;      
    
      var typeA = a.GetType();
      var typeB = b.GetType();
    
      if (typeA.Equals(typeB)) return a.Equals(b);
    
      var fieldsA = typeA.GetFields().Where(field => field.IsPublic).ToArray();
      var fieldsB = typeB.GetFields().Where(field => field.IsPublic).ToArray();
    
      if (fieldsA.Length != fieldsB.Length) return false;
    
      foreach(var field in fieldsA)
      {
         var other = fieldsB.FirstOrDefault(f => f.FieldType.Equals(field.FieldType) && f.Name.Equals(field.Name));
         if (other == null) return false;
    
         if (!field.GetValue(a).Equals(other.GetValue(b))) return false;  
      }
    
      return true;
    }
    

    【讨论】:

      【解决方案3】:

      好的,我认为您在这里遗漏了一些要点......

      首先,平等是什么意思?

      当两个对象拥有相同的引用时它们是否相等? 当他们拥有相同的共同财产时,他们是否平等? 还是什么时候?

      第二(也许更重要),为什么需要检查你不知道的对象的相等性?

      如果您甚至不知道对象的类型,那么说它们相等有什么意义?你甚至不能使用它们...

      如果您知道对象的类型,那么您就知道如何比较它们。

      您添加了场景案例 #4,为什么在您不知道任何类型的情况下比较两个不同类型的对象?

      在OOP中,不能比较不同类型的对象,因为没有意义,不能比较苹果和梨……

      这就是为什么我们通常创建包含不同类型的公共部分的接口,或者我们创建方法来将对象类型转换为另一种类型。

      我在这里给出的解决方案意味着您可以控制对象的实现。

      您可能希望重载 Equals() 方法(继承自 Object)。

      public class EmpPerson
      {
          public int ID { get; set; }
          public string Name { get; set; }
          public string Address { get; set; }
      
          public override bool Equals(object obj)
          {
              EmpPerson cmp = (EmpPerson)obj;
              return ID.Equals(cmp.ID);
          }
      }
      

      并且每当您需要比较它们时:

      obj1.Equals(obj2);
      

      然而,这带来了对象必须是同一类型的限制,无论是什么类型。

      注意:这里还没有实现错误检查,你需要做...

      【讨论】:

      • 我正在从服务中获取对象。我不知道,它是什么类型的对象。这就是问题所在。
      • @IRPunch 好的,我以为您确实为对象编写了代码。那你想要什么?有没有可能比较两个你不知道它们是什么的东西?
      • 看看场景#4
      【解决方案4】:

      另一种可能性是序列化对象并比较序列化的输出。

      Binary serialization for deep object comparison

      这可以是二进制或 xml,或其他。这是非常通用的,您可以使用开箱即用的实用程序来影响序列化行为。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-08-10
        • 2017-07-31
        • 2011-06-16
        • 1970-01-01
        • 2016-08-21
        • 2013-02-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多