2010-03-26 4 views
1

У меня есть коллекция объектов того же типа, назовем его DataItem. Пользователь может просматривать и редактировать эти элементы в редакторе. Также должно быть возможным сравнивать и объединять разные элементы, то есть какой-либо diff/merge для экземпляров DataItem.Функция Diff/Merge для объектов (не файлов!)

Функциональность DIFF должна сравнивать все (релевантные) свойства/поля элементов и обнаруживать возможные различия. Затем функциональность MERGE должна быть способна объединить два экземпляра, применив выбранные различия к одному из элементов.

Например (псевдо объекты):

DataItem1 {     DataItem2 { 
    Prop1 = 10     Prop1 = 10 
    Prop2 = 25     Prop2 = 13 
    Prop3 = 0     Prop3 = 5 
    Coll = { 7, 4, 8 }   Coll = { 7, 4, 8, 12 } 
}       } 

Теперь пользователь должен быть предоставлен список различий (т.е. Prop2, Prop3 и Coll), и он должен быть в состоянии выбрать, какие различия он хочет для устранения путем присвоения значения от одного элемента другому. Он также должен быть в состоянии выбрать, хочет ли он присвоить значение от DataItem1 до DataItem2 или наоборот.

Существуют ли общие практики, которые должны использоваться для реализации этой функциональности?

Так же редактор должен также обеспечить функциональность отмены/повтора (с использованием шаблона Command), я думал о повторном использовании ICommand реализации, потому что оба сценария в основном справиться с имущественными заданиями, изменениями коллекции, и так далее .. Моя идея состояла в том, чтобы создать объекты Difference с объектами ICommand, которые могут быть использованы для выполнения операции слияния для данного Difference.

КТ: Язык программирования будет C# с .NET 3.5SP1/4.0. Тем не менее, я думаю, что это скорее вопрос, не зависящий от языка. Любой шаблон дизайна/идея/приветствуются!

ответ

1

Это почти что я делаю. У меня есть класс «Diff» для объекта, который использует класс PropertyDiff для сравнения значений свойств с помощью Reflection. Это слишком много, чтобы вставить весь код в SO, но это должно дать вам представление. Затем отображается коллекция неравных объектов PropertyDiff для пользователя, который может выбрать, какие из них сохранить или удалить. Мы используем NHibernate, поэтому объекты меняются в памяти, а затем все изменения сохраняются в транзакции. У нас была более старая версия, которая создала коллекцию команд SQL, и это сработало, но вы должны быть осторожны, чтобы команды выполнялись в том же порядке и в транзакции. Самое худшее, что может случиться, - это если возникает исключение, и оба объекта - FUBAR.

Класс PropertyDiff представляет сравнение между тем же свойством на двух объектах. Это работает только для простых свойств и существует отдельный код для поддержки коллекций.

public class PropertyDiff 
{ 
    private bool _isEqual; 

    public PropertyDiff(string propertyName, object xvalue, object yvalue) 
    { 
     PropertyName = propertyName; 
     Xvalue = xvalue; 
     Yvalue = yvalue; 
     _isEqual = Xvalue == Yvalue; 
    } 

    public string PropertyName { get; private set; } 
    public object Xvalue { get; private set; } 
    public object Yvalue { get; private set; } 
    public bool IsEqual 
    { 
     get { return _isEqual; } 
    } 

    internal static IList<PropertyDiff> GetPropertyDiffs(IEnumerable<string> properties, object x, object y) 
    { 
     if (x.GetType() != y.GetType()) 
     { 
      throw new ArgumentException("Objects must be of same type"); 
     } 

     var list = new List<PropertyDiff>(); 
     var t = x.GetType(); 

     foreach (string propertyName in properties) 
     { 
      PropertyInfo pi = t.GetProperty(propertyName); 
      if (pi != null) 
      { 
       object xVal = pi.GetValue(x, null); 
       object yVal = pi.GetValue(y, null); 
       PropertyDiff propDiff = new PropertyDiff(propertyName, xVal, yVal); 
       list.Add(propDiff); 
      } 
     } 
     return list; 
    } 
} 

А класс CompanyDiff:

public class CompanyDiff 
    { 
     private List<string> _propertyNames; 
     private IList<PropertyDiff> _propertyDiffs; 

     public CompanyDiff(Company companyX, Company companyY) 
     { 
      this.CompanyX = companyX; 
      this.CompanyY = companyY; 

      // Build list of property names to be checked 
      _propertyNames = new List<string>() 
          { 
           "Type", 
           "Name", 
           "DBA" 
           // etc. 
          }; 

      _propertyDiffs = PropertyDiff.GetPropertyDiffs(_propertyNames, this.CompanyX, this.CompanyY); 
    } 

    public Company CompanyX { get; private set; } 
    public Company CompanyY { get; private set; } 

    public IList<PropertyDiff> PropertyDiffs 
    { 
     get { return _propertyDiffs; } 
    } 
} 
+0

Ого, я не ожидал, что полный исходный код. :) Благодаря! Я также думал об использовании отражения. Однако я планировал не использовать его из-за проблем с производительностью. Вместо этого я хотел реализовать интерфейс «IDiffable» в каждом классе с помощью метода «Compare (...)»). Какой опыт вы внесли в ваш подход, основанный на размышлениях (по производительности)? Мне придется сравнивать коллекции около 2000 объектов с примерно 50 свойствами каждый (не в одном классе, но учитывается рекурсивно). – gehho

+0

Я не оценил производительность, потому что все было хорошо.Это несколько процесс исключения (дублированная компания вошла и т. Д.) Для нас, поэтому производительность не является основной задачей. Мой совет заключается в том, чтобы использовать самый легкий подход, используя рефлексию и перефакторировать его, если есть реальная проблема с производительностью в мире, т. Е. Преждевременно оптимизировать. –

+0

Спасибо. Возможно, я также дам основанный на размышлении подход сначала. Затем я увижу, соответствует ли он моим требованиям к производительности. – gehho

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