2009-04-28 97 views
6

我需要在基类中编写一个通用方法,该方法接受2个对象作为参数并比较它们的相等性。比较2个自定义对象 - C#

例:

public abstract class BaseData 
{ 

    public bool AreEqual(object O1, object O2) 
    { 
    //Need to implement this 
    } 
} 

public class DataTypeOne : BaseData 
{ 
    public string Name; 
    public string Address; 
} 

public class DataTypeTwo : BaseData 
{ 
    public int CustId; 
    public string CustName; 
} 

AreEqual()方法将接受的DataTypeOne 2个实例或DataTypeTwo 2个实例。

我的猜测是我需要使用反射?如果可以更易读/简洁,我可以使用LINQ。

编辑: 我想在基类中实现此方法的原因是因为项目的限制。有大量的开发人员在派生类上工作。通过在基类中实现这一点,我想让他们少担心一件事。

+0

为什么不重写Object.Equals? – Paco 2009-04-28 14:05:54

+0

为什么你需要在基类中实现AreEqual(以及为什么没有泛型)?如果AreEqual是抽象的,DataTypeOne和DataTypeTwo实现AreEqual,那么这是一个更清晰的解决方案。简而言之:常见的AreEqual方法的原因是什么? – boj 2009-04-28 14:07:52

回答

13

(假设你想要的是两个对象是否相等的所有字段进行比较。)

通常情况下,你就懒得使用反射对于这一点,你只是拿自己的每个字段。 IEquatable<T>接口是为此目的而存在的,您也可能想要覆盖有关类型的Object.Equals()。例如:

public class DataTypeTwo : BaseData, IEquatable<DataTypeTwo> 
{ 
    public int CustId; 
    public string CustName; 

    public override int GetHashCode() 
    { 
     return CustId^CustName.GetHashCode(); // or whatever 
    } 

    public override bool Equals(object other) 
    { 
     return this.Equals(other as DataTypeTwo); 
    } 

    public bool Equals(DataTypeTwo other) 
    { 
     return (other != null && 
       other.CustId == this.CustId && 
       other.CustName == this.CustName); 
    } 
} 

另外,还要考虑你的类型是否是有意义的,而不是struct。值类型通过逐字段比较自动比较相等性。

请注意,通过覆盖Equals,您基本实现了您试图用“主等号方法”方案实现的内容(在我看来)。也就是说,使用DataTypeTwo的人将能够自然地测试平等,而不必知道任何关于您的API的特殊情况 - 他们只会像使用其他东西一样使用Equals

编辑:感谢贾里德提醒我关于GetHashCode。您还需要覆盖它以通过确保任何两个“相等”的对象也返回相同的哈希码来保持哈希表中的正常行为。

+1

你仍然需要覆盖GetHashCode – JaredPar 2009-04-28 14:06:35

+0

为什么你需要GetHashCode,等于不足? – 2009-04-29 06:15:41

+1

为了改变平等比较行为,请不要将类更改为结构体。微小的数据类型,如笛卡尔坐标,预计会以某种“按价值”的方式表现得很好;但是另一个程序员将​​会认为是一个类的数据结构不应该被作为结构来进行价值比较 - 你也将不可见地改变行为。初始化和(最重要的)分配。 – perfectionist 2013-09-02 09:53:39

0

是的,您将不得不使用反射,因为基类对派生类一无所知。但为什么你想在基类中实现该功能?为什么不在派生类中?

此外还有一个通过重写Object.GetHashCode()和Object.Equals()来完成此操作的标准方法。

1

我可能会做这样的事情:

public abstract class BaseData : IEquatable<BaseData> 
{ 
    public abstract bool Equals(BaseData other); 
} 

public class DataTypeOne : BaseData 
{ 
    public string Name; 
    public string Address; 

    public override bool Equals(BaseData other) 
    { 
     var o = other as DataTypeOne; 
     if(o == null) 
      return false; 
     return Name.Equals(o.Name) && Address.Equals(o.Address); 
    } 
} 

public class DataTypeTwo : BaseData 
{ 
    public int CustId; 
    public string CustName; 

    public override bool Equals(BaseData other) 
    { 
     var o = other as DataTypeTwo; 
     if (o == null) 
      return false; 
     return CustId == o.CustId && CustName.Equals(o.CustName); 
    } 
} 
+0

也许一个解释,为什么它是“疯狂”会很好。 – madcolor 2009-04-28 14:22:36

4

这就是我想出了使用反射。希望能帮助到你。

public bool AreEqual(object obj) 
    { 
     bool returnVal = true; 

     if (this.GetType() == obj.GetType()) 
     { 
      FieldInfo[] fields = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); 

      foreach (FieldInfo field in fields) 
      { 
       if(field.GetValue(this) != field.GetValue(obj)) 
       { 
        returnVal = false; 
        break; 
       } 
      } 
     } 
     else 
      returnVal = false; 

     return returnVal; 
    } 
2

不要这样做。继承是要走的路,每个类都应该在必要时重写Equal和GetHashCode。

也许你现在可以从这些开发者那里完成一些工作,但是在将来当产品需要维护时,我会回来咬你。

说真的,只是试图找到另一种方式来帮助。

0
public void CompareTwoObjects() 
{ 
    try { 
     byte[] btArray = ObjectToByteArray(object1); //object1 is you custom object1 
     byte[] btArray2 = ObjectToByteArray(object2); //object2 is you custom object2 
     bool result = ByteArrayCompare(btArray, btArray2); 
    } catch (Exception ex) { 
     throw ex; 
    } 
} 

public byte[] ObjectToByteArray(object _Object) 
{ 
    try { 
     // create new memory stream 
     System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream(); 

     // create new BinaryFormatter 
     System.Runtime.Serialization.Formatters.Binary.BinaryFormatter _BinaryFormatter 
      = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 

     // Serializes an object, or graph of connected objects, to the given stream. 
     _BinaryFormatter.Serialize(_MemoryStream, _Object); 

     // convert stream to byte array and return 
     return _MemoryStream.ToArray(); 
    } catch (Exception _Exception) { 
     // Error 
     Console.WriteLine("Exception caught in process: {0}", _Exception.ToString()); 
    } 

    // Error occured, return null 
    return null; 
} 

public bool ByteArrayCompare(byte[] a1, byte[] a2) 
{ 
    if (a1.Length != a2.Length) 
     return false; 

    for (int i = 0; i < a1.Length; i++) 
     if (a1[i] != a2[i]) 
      return false; 

    return true; 
}