2010-05-12 134 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需求分拆出来,它的所有开源代码都可以使用,因此您可以随意使用它。如果不是完全适合您的需求,这可能是一个很好的开始。