通用对象比较diff例程

时间:2010-05-12 11:49:49

标签: c# generics diff

问题源于数据库表的比较。假设我们将左行和左右行放在实例右侧的同一类型中。我们有许多桌子和各自的类型。

如何实现或多或少的通用例程,从而产生差异集合,例如
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 ) ;   

我的问题是我不知道如何避免重复每种类型的相似代码。对象群可能没问题。但在diff方法中我必须编码

if Left.Text1.Equals ( Right.Text1 ) 

等在一种方法中

if Left.Text3.Equals ( Right.Text3 ) 

以其他方法等等

2 个答案:

答案 0 :(得分: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
}

答案 1 :(得分:1)

我创建了一个库来做这件事并提供一些额外的元数据。不幸的是,它依赖于MVC ModelMetadataDataAnnotations来为非技术用户提供差异的“可读版本”。因此,它将使用您的DisplayName作为属性而不是其实际属性名称。

但它确实提供了为您自己的用途获取diff的编程表示的能力,而不是使用“可读”扩展。

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要求,它是全部开源的,所以你可以随意破解它。如果不是完全符合您的需求,它可能是一个好的起点。