Функциональность Diff / Merge для объектов (не файлов!) - PullRequest
1 голос
/ 26 марта 2010

У меня есть коллекция объектов одного типа, назовем это DataItem. Пользователь может просматривать и редактировать эти элементы в редакторе. Также должна быть возможность сравнивать и объединять разные элементы, то есть, что-то вроде diff / merge для DataItem экземпляров.

Функциональность 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 или наоборот.

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

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

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

1 Ответ

1 голос
/ 26 марта 2010

Это почти то, что я делаю. У меня есть класс «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; }
    }
}
...