将操作<t>存储在堆栈<t>中,用于UndoManager </t> </t>

时间:2014-01-07 22:06:27

标签: c# delegates stack

我想跟踪课程中的所有属性更改。我认为可以通过将每个“撤消”操作推送到一堆操作代表来跟踪每个事件。当调用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>>();        
    }        

}

1 个答案:

答案 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应该是外部调用的。