The usual procedure for comparing objects

The question is related to mapping database tables. Let's say we put the left row in the Left instance and Right in the instance Right of the same type. And we collect many tables and related types.

How to implement a more or less general procedure that leads to collection of differences, for example,
propertyName, leftValue, rightValue for each such pair of instances of the same type. Apart from the general comparison algorithm, since leftValue and rightValue can be anything (a pair of strings or int or DateTime or Guid), it is not obvious how to combine it all in one collection.

EDIT:

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 ) ;   

      

My problem is that I don't know how to avoid repeating this perfectly similar code for each type. This may be normal for objects. But in diff methods I have to code

if Left.Text1.Equals ( Right.Text1 ) 

      

etc. one way

if Left.Text3.Equals ( Right.Text3 ) 

      

etc. another way

+2


a source to share


2 answers


Not sure if this is exactly what you want, but this method can do a shallow comparison of two objects corresponding to properties and compare them to make sure they are equal.

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());
}

      



Using this method, you can compare two objects based on matching property names. For instance:

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
}

      

+3


a source


I created a library to do this and provide some additional metadata. Unfortunately, it relies on the MVC ModelMetadata

, and DataAnnotations

to provide "readable version of the" diff for non-technical users. This way it will use yours DisplayName

for the property instead of its actual property name.

But it does provide a programmatic view of the diff for your own purposes instead of using the "Readable" extensions.

https://github.com/paultyng/ObjectDiff

For objects such as:

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" } 
};

      



Readable diff extensions output something like:

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

      

But a programmatic diff will give you information about each property and list item, and you can do it whatever you want.

I plan to share the MVC requirement in the future, all of its open source, so you can hack it however you want. This can be a good place to start if not exactly tailored to your needs.

+1


a source







All Articles