2010-03-26 28 views
1

我有一個相同類型的對象的集合,我們稱之爲DataItem。用戶可以在編輯器中查看和編輯這些項目。還應該可以比較和合並不同的項目,即某種DataItem實例的差異/合併。對象的差異/合併功能(不是文件!)

DIFF功能應比較項目的所有(相關)屬性/字段並檢測可能的差異。 MERGE功能應該能夠通過將選定差異應用於其中一個項目來合併兩個實例。

例如(僞對象):

DataItem1 {     DataItem2 { 
    Prop1 = 10     Prop1 = 10 
    Prop2 = 25     Prop2 = 13 
    Prop3 = 0     Prop3 = 5 
    Coll = { 7, 4, 8 }   Coll = { 7, 4, 8, 12 } 
}       } 

現在,用戶應提供一個差異列表(即Prop2Prop3Coll),他應該能選擇他想要哪個差異通過將一個項目的值分配給另一個項目來消除。他還應該能夠選擇是否要將DataItem1的值指定爲DataItem2,反之亦然。

是否有常用的實踐應該用來實現這個功能?

由於相同的編輯器還應該提供撤銷/重做功能(使用Command模式),我在想重用ICommand實現,因爲這兩種方案基本上是與財產分配,集合改變處理,等等.. 。我的想法是創建Difference對象,其中ICommand屬性可用於執行此特定Difference的合併操作。

Btw:編程語言將C#與.NET 3.5SP1/4.0。但是,我認爲這更像是一個與語言無關的問題。任何設計模式/想法/歡迎!

回答

1

這就是我所做的。對於使用PropertyDiff類使用Reflection來比較屬性值的對象,我有一個「Diff」類。將所有代碼粘貼到SO中太過分了,但這應該會給你一個想法。然後將不等於PropertyDiff對象的集合顯示給可以選擇保留或放棄哪些對象的用戶。我們使用NHibernate,以便在內存中更改對象,然後所有更改都保留在事務中。我們確實有一個較早的版本,它構建了一組SQL命令並且工作得很好,但是您必須小心,這些命令是以相同的順序和事務執行的。可能發生的最糟糕的事情是如果發生異常並且兩個對象都是FUBAR。

PropertyDiff類表示兩個對象上相同屬性之間的比較。這僅適用於簡單的屬性,並且存在用於維護集合的單獨代碼。

public class PropertyDiff 
{ 
    private bool _isEqual; 

    public PropertyDiff(string propertyName, object xvalue, object yvalue) 
    { 
     PropertyName = propertyName; 
     Xvalue = xvalue; 
     Yvalue = yvalue; 
     _isEqual = Xvalue == Yvalue; 
    } 

    public string PropertyName { get; private set; } 
    public object Xvalue { get; private set; } 
    public object Yvalue { get; private set; } 
    public bool IsEqual 
    { 
     get { return _isEqual; } 
    } 

    internal static IList<PropertyDiff> GetPropertyDiffs(IEnumerable<string> properties, object x, object y) 
    { 
     if (x.GetType() != y.GetType()) 
     { 
      throw new ArgumentException("Objects must be of same type"); 
     } 

     var list = new List<PropertyDiff>(); 
     var t = x.GetType(); 

     foreach (string propertyName in properties) 
     { 
      PropertyInfo pi = t.GetProperty(propertyName); 
      if (pi != null) 
      { 
       object xVal = pi.GetValue(x, null); 
       object yVal = pi.GetValue(y, null); 
       PropertyDiff propDiff = new PropertyDiff(propertyName, xVal, yVal); 
       list.Add(propDiff); 
      } 
     } 
     return list; 
    } 
} 

而且CompanyDiff類:

public class CompanyDiff 
    { 
     private List<string> _propertyNames; 
     private IList<PropertyDiff> _propertyDiffs; 

     public CompanyDiff(Company companyX, Company companyY) 
     { 
      this.CompanyX = companyX; 
      this.CompanyY = companyY; 

      // Build list of property names to be checked 
      _propertyNames = new List<string>() 
          { 
           "Type", 
           "Name", 
           "DBA" 
           // etc. 
          }; 

      _propertyDiffs = PropertyDiff.GetPropertyDiffs(_propertyNames, this.CompanyX, this.CompanyY); 
    } 

    public Company CompanyX { get; private set; } 
    public Company CompanyY { get; private set; } 

    public IList<PropertyDiff> PropertyDiffs 
    { 
     get { return _propertyDiffs; } 
    } 
} 
+0

哇哦,我沒想到完整的源代碼。 :) 謝謝!我也想過使用反射。但是,由於涉及的性能問題,我計劃不使用它。相反,我想用'Compare(...)'方法在每個類中實現'IDiffable'接口。你使用基於反思的方法(性能方面)有什麼經驗?我將不得不將大約2000個對象的集合與大約50個屬性(不是在一個類中,而是遞歸計數)進行比較。 – gehho 2010-03-26 16:36:34

+0

我沒有衡量性能,因爲它沒有問題。這對我們來說是一個例外程序(重複的公司進入等),所以表現不是主要目標。我的建議是採用反射的最簡單方法,並在存在真實世界性能問題時重新分解它,即不要過早優化。 – 2010-03-26 17:14:49

+0

謝謝。也許我也會首先嚐試基於反思的方法。然後我會看看它是否符合我的性能要求。 – gehho 2010-03-29 07:02:54