2012-01-19 105 views
5

我有一個有很多屬性的類。淺拷貝足以完全複製對象。簡單地在c中比較兩個對象的屬性#

我需要比較一個對象只是爲了檢查它是否包含與另一個完全相同的值。

我的想法:

第一個也是最明顯的解決方案就是創建每個屬性,一個接一個比較龐大的方法塊。

第二,將序列化每個對象和散列文件或做一些對它的md5校驗和。 (這實際上工作)。

第三種是對物體進行某種反射,這會使第一種選擇自動化,但是會增加複雜性。

速度並不是真正的問題。

有興趣聽​​到思想或任何其他方法我失蹤做這樣的事情。

編輯: 謝謝大家。我的解決方案:(修改爲現在是遞歸通用項目)。

public static bool IsSame<T>(T objA, T objB) 
     { 
      var type = typeof(T); 
      var properties = type.GetProperties(); 
      foreach (var pi in properties.Where(a => a.CanRead)) 
      { 
       if (pi.Name == "Item") 
       { 
        var piCount = properties.FirstOrDefault(a => a.Name == "Count"); 
        int count = -1; 
        if (piCount != null && piCount.PropertyType == typeof(System.Int32)) 
         count = (int)piCount.GetValue(objA, null); 
        if (count > 0) 
        { 
         for (int i = 0; i < count; i++) 
         { 
          dynamic child1 = pi.GetValue(objA, new object[] { i }); 
          dynamic child2 = pi.GetValue(objB, new object[] { i }); 
          return IsSame(child1, child2); 
         } 
        } 
       } 
       else 
       { 
        var val1 = type.GetProperty(pi.Name).GetValue(objA, null); 
        var val2 = type.GetProperty(pi.Name).GetValue(objB, null); 
        if (val1 != val2 && (val1 == null || !val1.Equals(val2))) 
         return false; 
       } 
      } 
      return true; 
     } 
+2

我會去反思,除非類結構不容易改變。如果它*不會*改變,我會選擇第一個解決方案,而不是(易於閱讀,易於維護) – Alex

+0

http://stackoverflow.com/questions/506096/comparing-object-properties-in-c-sharp有用反射解決方案。 – Giedrius

回答

6

大多數串行旨在確保序列化和反序列化過程中的數據保持其完整性,不產生一致的序列化格式。我會避免爲此目的使用序列化。

您可以考慮實施IEquatable,讓每個實例能夠將自己與相同類型的實例進行比較。或者一個班級爲你實施IEqualityComparer做比較。他們如何做這個比較可能是一個接一個地比較特性或使用反思的「大方法」。

反射可以是一種相當快速和簡單的方式來實現您的目標,但可能導致問題(例如,如果有人添加屬性到您的類型不應包括比較相等),但顯然相反是也是如此(有人添加了一個應該檢查相等性的屬性,但是不會更新相等性比較)。您使用哪種方法通常應由團隊對每種方法的適應程度以及班級的使用環境決定。

在你的情況,我可能會建議使用基於反射的方法,因爲你想檢查一個淺克隆操作的結果,所以所有的屬性應該是平等的。另外,我建議使用MemberwiseClone方法來創建克隆,這將減少對這種嚴格測試的需求。

+3

我想你會想IEquatable而不是IComparable。 IComparable用於排序,而不是等價。 –

+0

@ForgottenSemicolon謝謝,回覆更新。 –

+0

+1提供良好的接口來查看實現。 – pseudocoder

1

另一個想法是,如果屬性返回簡單值類型,則可以將它們分組爲它們自己的不可變值類型。例如,如果你有一個客戶的屬性string Address1string Address2string Citystring Statestring Zip,你可以創建一個值類型地址,它實現了自己的相等比較器並使用它。

不確定這是否適用於您的情況,但我發現,當我有一個具有很多屬性的類時,通常可以這樣做,並且它傾向於使我的類更簡單,更容易推理關於。

6

第三個選項(反射)將是最慢的,但它也是最強大/可測試的。

哈希碼與第一個選項非常相似,因爲您必須調用所有成員變量,所以1和2會要求您在每次修改成員變量列表時都更新.Equals(obj).GenerateHash()方法。

這裏是一些代碼,讓你開始:

 foreach (FieldInfo field in this.GetType().GetFields()) 
     { 
      if (o[field.Name] == null) 
      { 
       if (!field.GetValue(this).Equals(o[field.Name])) 
        return false; 
      } 
      else 
      { 
       return false; 
      } 
     } 

     return true; 
1

如果您序列化,你必須指定每個字段/屬性的序列化,以確保所有數據序列化的int相同的順序。但是你要實現的只是在外部類中實現GetHashCode()。

GetHashCode()有一些關於如何覆蓋它的例子,所以先看看那裏。

如果你的班級有很多字段,並且你不想手動編寫所有的代碼。您可以使用反射來自動生成代碼。如果您的類不時發生變化,那麼您可以在T4模板中使用GetHashCode()實現創建一個部分類。