04.03.2009

C# EditableObject: Commit and Rollback для объекта.

Иногда возникает необходимость такой работы над объектом, когда нужно иметь возможность отменить все изменения в нем (rollback). Например, пользователь редактирует свойства объекта, а потом отказывается сохранять изменения. Можно загрузить объект заново с сервера, но проще отменить изменения на стороне клиента. Для этого можно использовать шаблонный класс EditableObject<>. Он создает для объекта второй экземпляр, с которым и производятся все действия. В случае отмены действий экземпляр просто пересоздается заново копированием оригинала. А в случае применения действий данные из копии переносятся в оригинал, используя рефлексию (reflection).


public class EditableObject<TObjectType>
where TObjectType : ICloneable, new()
{
/// Архивная версия объекта</summary>
private TObjectType _original;

/// Текущий объект</summary>
private TObjectType _editable;

/// Текущий объект</summary>
public TObjectType Current
{
get { return _editable; }
}

public EditableObject(TObjectType objectInst)
{
if (objectInst != null)
{
_original = objectInst;

BeginEdit();
}
else
{
throw new ArgumentNullException(
"Объект objectInst должен быть не null", (Exception)null);
}
}

/// Начать редактировать объект
private void BeginEdit()
{
_editable = (TObjectType)_original.Clone();
}

/// Отменить все сделанные изменения
public void CancelEdit()
{
BeginEdit();
}

/// Завершить редактирование объекта
public void EndEdit()
{
Copy(_editable, _original);
}

/// Копирование объектов
private static void Copy(
TObjectType fromObject, TObjectType toObject)
{
foreach (FieldInfo fInfo in typeof(TObjectType).GetFields(
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance))
{
fInfo.SetValue(toObject, fInfo.GetValue(fromObject));
}
}
}


Пример использования:


...
EditableObject<TestClass> editableTestInst =
new EditableObject<TestClass>(testInst);
...
try
{
...
// применить изменения
editableTestInst.EndEdit();
}
catch(Exception)
{
// отменить все изменения
editableTestInst.CancelEdit();
}


Свойство Current возвращает объект который можно редактировать.

Комментариев нет: