2010-05-12 4 views
2

Вопрос связан с сопоставлением таблиц базы данных. Скажем, мы помещаем левую строку в экземпляр Left и Right на экземпляр Right того же типа. И мы собираем много таблиц и соответствующих типов.Общая классификация сравнения объектов

Как реализовать более или менее общую процедуру, приводящую к сбору различий, например.
propertyName, leftValue, rightValue для каждой такой пары экземпляров того же типа. Помимо общего алгоритма сравнения, поскольку leftValue и rightValue могут быть любыми (пара строк или int или DateTime или Guid), не очевидно, как объединить все это в одной коллекции.

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

Моя проблема заключается в том, что я не знаю, как избежать повторения этого весьма похожего кода для каждого типа. Это может быть нормально для объектов. Но в дифф методы, которые я должен кодировать

if Left.Text1.Equals (Right.Text1) 

и так далее в одном методе

if Left.Text3.Equals (Right.Text3) 

и так далее в другом методе

+0

Можете ли вы поместить некоторый код psuedo, описывая это. –

+0

Одна вещь, которую я сделал, это сделать метод, который возвращает список значений (по порядку), которые являются «важными». Затем я использую этот список (а не фактический) для сравнения Equality и создания Hash.Это похоже на несколько более автоматизированный процесс, как упоминается в ответе Мэтью, но помещает «выбор поля импорта» в руки объекта (атрибуты также могут использоваться, я думаю). Это можно сделать очень легко через несколько объектов с интерфейсом и статическим помощником или методом расширения - должно быть меньше ~ 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 ModelMetadata и DataAnnotations, чтобы предоставить «читаемую версию» diff для нетехнических пользователей. Поэтому он будет использовать ваш DisplayName для свойства вместо его фактического имени свойства.

Но это дает возможность получить программное представление diff для ваших собственных целей вместо использования «Readable» расширений.

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

читаемый расширения дифференциалов выход что-то вроде:

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 в будущем, все его открытые источники, так что вы можете взломать его так, как вы. Это может быть хорошее место для начала, если не точное соответствие вашим потребностям.

Смежные вопросы