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
a source to share
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
}
a source to share
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.
a source to share