2014-01-07 21 views
0

我想跟蹤在類的所有屬性更改。我認爲可以通過將每個「撤消」操作推送到堆棧的Action Delegate來跟蹤每個事件。當撤消()被調用時,獲取最後撤消事件的引用並調用它,但是這個 似乎不起作用。另外,當我嘗試從堆棧彈出()最後一個操作時,它不會從堆棧中移除。在堆棧<T>存儲行動<T>爲UndoManager的

也許這不是最好的方法?這只是一個代表我的學習過程,所以也許我的做法是錯誤的。

例子:

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>>();   
    }   

} 

回答

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是應該從外部調用的)。

+0

過度使用這總是表示在我的經驗某處的問題。必須同意你一個暴露堆棧。 mc.MyOperations = new Stack >();將是baaaad。 –

+0

@TonyHopkinson一切都很糟糕。你可以清除堆棧,你可以彈出一個動作而不用調用它來基本上擦除歷史的一部分,你可以在不改變對象的情況下添加項目,以便撤銷實際上做一個新的操作,不會被撤消,等等從字面上看,任何對它做的任何事情都是不好的,除非可能檢查計數。 – Servy

+0

是的,但公共MyOperations {get;私人設置}將朝着正確的方向邁出一步。和你一樣,我無法想象爲什麼你希望能夠將額外的項目推送到課堂邏輯之外的堆棧中。根本不喜歡那個價值業務。一個真正的殺手會出現在有人出現時說我想重做。 :( –

相關問題