2010-05-12 194 views
2

該問題源於數據庫表比較。比方說,我們將Left行放入實例Left並將右側放入同一類型的Right實例中。我們還有許多表格和相應的類型。通用對象比較比較例程

如何實現或多或少的泛型例程,導致差異集合例如
propertyName,leftValue,rightValue每個這樣的一對相同類型的實例。 除了通用比較算法,因爲leftValue和rightValue可以是任何東西(一對字符串或int或DateTime或Guid)並不明顯,如何將一個集合中的所有內容合併在一起。

編輯:

class OneOfManyTypesBasedOnTableRow 
{ 
    Guid uid, 
    int anotherId, 
    string text1, 
    string text2, 
    DateTime date1, 
    DateTime date2 
} 
class AnotherOfManyTypesBasedOnTableRow 
{ 
    Guid uid, 
    int anotherId, 
    string text3, 
    string text4, 
    DateTime date3, 
    DateTime date4 
} 

//For type 1 
OneOfManyTypesBasedOnTableRow Left = new Something().GetLeft() ; 
OneOfManyTypesBasedOnTableRow Right = new Something().GetRight() ; 
DiffCollection1 diff1 = comparer.GetDiffForOneOfManyTypesBasedOnTableRow (Left , Right) ; 

//For type 2 

AnotherOfManyTypesBasedOnTableRow Left = new SomethingElse().GetLeft() ; 
AnotherOfManyTypesBasedOnTableRow Right = new SomethingElse().GetRight() ; 
DiffCollection2 diff2 = comparer.GetDiffForAnotherOfManyTypesBasedOnTableRow (Left , Right) ; 

我的問題是,我不知道如何避免爲每個類型非常相似的代碼重複。對象羣體可能沒關係。但在差異方法我必須代碼

if Left.Text1.Equals (Right.Text1) 

等在一個方法

if Left.Text3.Equals (Right.Text3) 

等其他方法

+0

你可以把一些僞代碼描述這個。 – 2010-05-12 11:54:16

+0

我做的一件事就是創建一個返回值爲「重要」的值列表的方法。然後我使用該列表(而不是實際的)對象來比較平等並生成一個哈希。這與Mathew的回答中提到的稍微更加自動化的過程類似,但將「導入字段」選擇置於對象的手中(我猜也可以使用屬性)。使用接口和靜態幫助程序或擴展方法可以很容易地在多個對象上輕鬆完成此操作 - 每個類應少於8行代碼。 – 2011-01-15 21:30:10

回答

3

不知道這是否是你想要的是什麼,但這種方法可以對匹配屬性的兩個對象進行淺層比較,並比較它們以查看它們是否相等。

private static bool DoObjectsMatch(object object1, object object2) 
{ 
    var props1 = object1.GetType() 
        .GetProperties() 
        .ToDictionary<PropertyInfo,string,object>(p => p.Name, p => p.GetValue(object1, null)); 
    var props2 = object2.GetType() 
        .GetProperties() 
        .ToDictionary<PropertyInfo,string,object>(p => p.Name, p => p.GetValue(object2, null)); 
    var query = from prop1 in props1 
       join prop2 in props2 on prop1.Key equals prop2.Key 
       select prop1.Value == null ? prop2.Value == null : prop1.Value.Equals(prop2.Value); 

    return query.Count(x => x) == Math.Max(props1.Count(), props2.Count()); 
} 

使用此方法,您可以根據一個匹配屬性名稱比較兩個對象。例如:

class Thing 
{ 
    public int Id {get;set;} 
    public string Text{get;set;} 
} 

void Main() 
{ 
    var t1 = new Thing{ Id = 3, Text = "hi" }; 
    var t2 = new Thing{ Id = 3, Text = "hi" }; 
    var t3 = new Thing{ Id = 4, Text = "bye" }; 

    Console.WriteLine(DoObjectsMatch(t1,t2)); // True 
    Console.WriteLine(DoObjectsMatch(t2,t3)); // False 
} 
+0

我更喜歡稍微更詳細的「手動」方法,明確選擇「重要的價值」,但很好的一般答案。 – 2011-01-15 21:32:18

1

我創建了一個庫來完成此操作並提供一些額外的元數據。不幸的是,它依靠MVC ModelMetadataDataAnnotations爲非技術用戶提供diff的「可讀版本」。所以它會使用您的DisplayName作爲屬性而不是其實際的屬性名稱。

但它確實能夠爲您自己的用途獲取差異的程序化表示,而不是使用「可讀」擴展名。

https://github.com/paultyng/ObjectDiff

考慮對象,如:

var before = new 
{ 
    Property1 = "", 
    MultilineText = "abc\ndef\nghi", 
    ChildObject = new { ChildProperty = 7 }, 
    List = new string[] { "a", "b" } 
}; 

var after = new 
{ 
    Property1 = (string)null, 
    MultilineText = "123\n456", 
    NotPreviouslyExisting = "abc", 
    ChildObject = new { ChildProperty = 6 }, 
    List = new string[] { "b", "c" } 
}; 

的可讀DIFF擴展輸出類似:

ChildObject - ChildProperty: '6', was '7' 
List - [2, added]: 'c', was not present 
List - [removed]: No value present, was 'a' 
MultilineText: 
----- 
123 
456 
----- 
was 
----- 
abc 
def 
ghi 
----- 
NotPreviouslyExisting: 'abc', was not present 

但綱領性差異會爲您提供有關每個屬性和列表項信息你可以做到這一點你會做什麼。

我打算將未來的MVC需求分拆出來,它的所有開源代碼都可以使用,因此您可以隨意使用它。如果不是完全適合您的需求,這可能是一個很好的開始。