Hier ist eine Möglichkeit, es zu tun:
die command pattern verwenden, können Sie undoable Aktionen erstellen. Mit jeder Operation registrieren Sie die zugehörigen Befehle, sodass Sie die ausgeführten Befehle rückgängig machen können, wenn eine Fehlerbedingung auftritt.
Zum Beispiel könnte dies alles in ein transaktionsähnliches Kontextobjekt gehören, das IDisposable
implementiert und in einen using
Block einfügt. Die rückgängig zu machenden Aktionen würden in diesem Kontextobjekt registriert. Bei der Entsorgung wird, wenn nicht festgeschrieben, für alle registrierten Befehle "rückgängig machen" ausgeführt. Ich hoffe es hilft. Der Nachteil ist, dass Sie möglicherweise einige Methoden in Klassen konvertieren müssen. Dies könnte jedoch ein notwendiges Übel sein.
Codebeispiel:
using(var txn = new MyTransaction()) {
txn.RegisterCommand(new CreateUserFtpAccountCommand());
txn.RegisterCommand(new CreateUserFolderCommand());
txn.RegisterCommand(new SetUserPermissionCommand());
txn.RegisterCommand(new CreateVirtualDirectoryForUserCommand());
txn.Commit();
}
class MyTransaction : IDisposable {
public void RegisterCommand(Command command){ /**/ }
public void Commit(){ /* Runs all registered commands */ }
public void Dispose(){ /* Executes undo for all registered commands */ }
}
class UndoableCommand {
public Command(Action action) { /**/ }
public void Execute() { /**/ }
public void Undo{ /**/ }
}
Update:
Sie erwähnten, dass Sie Hunderte solcher reversibler Operationen haben. In diesem Fall können Sie einen funktionelleren Ansatz wählen und UndoableCommand
vollständig loswerden. Sie würden stattdessen Delegierten registrieren, wie folgt aus:
using(var txn = new MyTransaction()) {
txn.Register(() => ftpManager.CreateUserAccount(user),
() => ftpManager.DeleteUserAccount(user));
txn.Register(() => ftpManager.CreateUserFolder(user, folder),
() => ftpManager.DeleteUserFolder(user, folder));
/* ... */
txn.Commit();
}
class MyTransaction : IDisposable {
public void Register(Action operation, Action undoOperation){ /**/ }
public void Commit(){ /* Runs all registered operations */ }
public void Dispose(){ /* Executes undo for all registered and attempted operations */ }
}
Als Anmerkung, müssen Sie würde mit closures mit diesem Ansatz vorsichtig sein.
hast du nachgeschlagen ** transactionscope **? -> http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope%28v=vs.110%29.aspx –