2009-04-28 99 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; 
}