代码之家  ›  专栏  ›  技术社区  ›  MicMit

通用对象比较diff例程

  •  2
  • MicMit  · 技术社区  · 14 年前

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

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

    在其他方法中等等

    2 回复  |  直到 12 年前
        1
  •  3
  •   Matthew Manela    14 年前

    不确定这是否正是您想要的,但此方法可以对匹配属性的两个对象进行浅比较,并比较它们以查看它们是否相等。

    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
    }
    
        2
  •  1
  •   Paul Tyng    12 年前

    我创建了一个库来实现这一点,并提供了一些额外的元数据。不幸的是,它依赖于MVC ModelMetadata DataAnnotations 为非技术用户提供diff的“可读版本”。所以它会用你的 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
    

    但是编程的diff会给你关于每个属性和列表项的信息,你可以用它来做你想做的。

    我计划在未来分割MVC需求,它是所有开放源码的,所以您可以黑客攻击它。如果不能完全满足你的需要,这可能是一个很好的开始的地方。