我想跟踪课程中的所有属性更改。我认为可以通过将每个“撤消”操作推送到一堆操作代表来跟踪每个事件。当调用Undo()时,获取对上一个撤消事件的引用并调用它,但是这样 似乎不起作用。此外,当我尝试从堆栈中弹出()最后一个Action时,它不会从堆栈中删除。
也许这不是最好的方法?对于代表来说,这只是一个学习过程,所以也许我的方法是错误的。
示例:
MyClass mc = new MyClass();
mc.Value = "Test1";
Console.WriteLine("Add 1.{0}", mc.Value);
mc.Value = "Test2";
Console.WriteLine("Add 2.{0}", mc.Value);
mc.Undo();
Console.WriteLine("Undo: {0}", mc.Value);
Console.WriteLine("Stack size: {0}", mc.MyOperations.Count);
public interface IUndoManager<T>
{
void Add(Action<T> undoOperation);
}
public class MyClass : IUndoManager<MyClass> {
public Stack<Action<MyClass>> MyOperations {get;set;}
private String value;
public String Value
{
get { return this.value; }
set {
this.Add(x => this.Value = value);
this.value = value;
}
}
public void Add(Action<MyClass> undoOperation)
{
this.MyOperations.Push(undoOperation);
}
public void Undo() {
Action<MyClass> lastAction = this.MyOperations.Pop();
lastAction(this);// fire event
}
public MyClass() {
this.MyOperations = new Stack<Action<MyClass>>();
}
}
答案 0 :(得分:2)
你的错误在这里:
public String Value
{
get { return this.value; }
set
{
this.Add(x => this.Value = value);
this.value = value;
}
}
特别是这一行:
this.Add(x => this.Value = value);
撤消该值会调用属性setter ,它会向堆栈添加另一个操作。
在这种情况下,您希望访问基础值,而不是属性,以避免这种情况:
this.Add(x => this.value = value);
至于设计问题,我不会公开公开堆栈,也不会公开公开Add
方法。这些应该是每个类型的内部实现细节。让来电者弄乱可能会导致问题。
这就是为什么你似乎无法收缩你的筹码。调用Undo
并非“没有弹出值”,只是弹出值,然后重新放置一个以替换它。
另请注意,您要跟踪Action<MyClass>
而不仅仅是Action
,但在实际添加操作时,您不会使用该参数。如果您要让一堆操作接受参数,则使用参数而不是关闭this
。如果你打算使用闭包,你也可以从方法中删除参数并简化操作。
IUndoManager
进行Undo
操作可能也是有意义的。 (事实上,我甚至不知道为什么它需要Add
操作; Undo
应该是外部调用的。