Простая система отмены/повтора для С# POCO

Я использую POCO (объекты класса) для каждого типа данных в памяти. У меня есть множество функций, которые работают с ними и изменяют их по-разному. Каков простой способ добиться функциональности отмены/возврата с минимальными изменениями в коде? Некоторые идеи:

  • Журнал изменений с помощью ORM – Журналирование на уровне свойств. Методы, которые изменяют POCO, должны регистрировать каждое изменяемое ими свойство или изменять свойства через ORM вместо того, чтобы работать непосредственно с указанными POCO. ORM будет регистрировать изменения и иметь возможность вернуться при необходимости.

  • Глубокое клонирование и сравнение — шаблон Memento - Сохраняйте глубокие клоны объектов перед их изменением (тратится память впустую, медленно). После внесения изменений вызовите функцию, которая вычисляет различия в свойствах объекта (должна перебирать все свойства, медленно, утомительно, рекурсивно). Различия сохраняются в журнале, чтобы иметь возможность вернуться к ним позже.

  • Каждая команда поддерживает отмену/возврат — Шаблон команды — классический подход, но потребовал бы слишком много дополнений в коде. Я ищу что-то общее, и в идеале что-то, что не требует переписывания приложения с нуля.

Я не знаю типичных подходов к такого рода проблемам, но, учитывая их довольно распространенность, я уверен, что есть хорошие шаблоны для решения этой проблемы без особых хлопот. Знаете ли вы какой-либо шаблон/библиотеку, которая простым способом обрабатывает историю для POCO?

В настоящее время я просматриваю следующее, но все еще ищу лучшие подходы.


person Robin Rodricks    schedule 20.01.2014    source источник
comment
Вы не должны думать об отмене/повторении самих POCO; вы должны думать об отмене/повторении для состояния, которое они представляют. Чего именно вы пытаетесь достичь?   -  person Ant P    schedule 20.01.2014
comment
Вы, вероятно, ищете шаблон Memento, посмотрите здесь: stackoverflow.com/questions/8994433/   -  person Moeri    schedule 20.01.2014
comment
@Ant P - я использую POCO для первичных данных в приложении. Если я могу отменить/повторить изменения, внесенные в POCO, после этого я смогу довольно легко обновить графический интерфейс.   -  person Robin Rodricks    schedule 20.01.2014
comment
Я все еще говорю, что вы идете по этому пути неправильно - отслеживаемые изменения функциональности приложения принадлежат в вашим POCO, а не в архиве вашего POCO. Опять же, чего вы пытаетесь достичь? Ваш вопрос слишком абстрактен.   -  person Ant P    schedule 20.01.2014
comment
Я думаю, что «лучшее» решение будет использовать отражение, скомпилированное в деревья выражений. Но я не знаю ни одной такой существующей структуры.   -  person Jack    schedule 20.01.2014
comment
@Jack - отражение, скомпилированное в деревья выражений ?? Какие? Можете ли вы немного уточнить правильный ответ, чтобы я мог его построить?   -  person Robin Rodricks    schedule 20.01.2014
comment
Почему закрытое голосование? Что не так с этим вопросом?   -  person Robin Rodricks    schedule 20.01.2014
comment
CSLA.NET Framework содержит UndoableBase, который обрабатывает отмену и может быть легко изменен для повторного выполнения, заслуживает рассмотрения, даже если вы этого не делаете. используй это.   -  person Adam Houldsworth    schedule 20.01.2014
comment
@Robinicks Удалось ли вам найти хороший и эффективный способ? У меня именно такая проблема и я не могу найти правильное решение. Мои POCO не являются неизменными.   -  person Vahid    schedule 13.11.2018


Ответы (1)


Возможный высокоуровневый подход:

  1. Отметьте свойства вашего POCO с помощью virtual
  2. Перенаправить запросы на создание экземпляра объекта на пользовательскую фабрику для указанных классов (это легко, если вы уже используете внедрение зависимостей)
  3. В первый раз, когда ваша пользовательская фабрика получает запрос на создание экземпляра для одного из ваших целевых классов, используйте отражение, чтобы создать новый класс, который переопределяет целевые свойства (возможно, украшенный пользовательским атрибутом [UndoRedo]?)
  4. Переопределенная реализация set{} будет идентифицировать изменения и создавать объект идентификации изменения (который просто идентифицирует свойство, ссылку на объект и старое значение), который помещается в ваш стек изменений. А затем вызовите метод set базового класса. Вероятно, потребуется написать код на IL.
  5. Чтобы отменить изменения, извлеките идентификатор изменения из стека и примените старое значение к данному свойству в данной ссылке на объект, используя предпочитаемый вами подход.

В результате потребители поддерживаемых классов не заметят никакой разницы (кроме создания объекта, см. шаг 2).

person Jack    schedule 20.01.2014
comment
Эта библиотека codeproject делает что-то подобное, за исключением генерации кода/IL. Вы в основном заключаете каждое свойство в теги UndoRedo<>, и система регистрирует изменения для каждого свойства. codeproject.com/Articles/19550/ - person Robin Rodricks; 21.01.2014