带闭包的基本撤消/重做逻辑

时间:2016-07-21 05:58:38

标签: c# closures

我试图掌握c#中闭包的概念。基本上尝试使用闭包捕获值和xBefore和yBefore

这是我的代码

    int x = 0;
    int y = 0;

    Action PerformOperation(bool move, bool undo, int x1, int y1)
    {
        Action operationMove = null;
        Action operationUndo = null;
        int xBefore = 0;
        int yBefore = 0; 

        operationMove = () => 
        {
                xBefore = x;
                yBefore = y;
                x = x1;
                y = y1;
                Debug.Log(" -- Move Operation -- " + " xBefore " +xBefore+ " yBefore " +yBefore+ " x " +x+ " y " +y);
        };

        operationUndo = () => 
        {
                x = xBefore;
                y = yBefore;
                Debug.Log(" -- Undo Operation -- " + " xBefore " +xBefore+ " yBefore " +yBefore+ " x " +x+ " y " +y);
        };

        if (move)
            return operationMove;
        if (undo)
            return operationUndo;
        return null;
    }

然后在我的启动功能中调用Action

Action operation = PerformOperation (true,false,5,5);
        operation ();
        operation       = PerformOperation (true, false, 15, 15);
        operation ();
        operation       = PerformOperation (true, false, 30, 30);
        operation ();
        operation       = PerformOperation (false, true, 10, 10);
        operation ();

基本上,根据在PerformOperation中传递的布尔变量执行移动或撤消操作。所以xBefore和yBefore在通过operationMove操作更新之前跟踪x和y。 operationUndo以类似的方式调用,然后最终返回两个动作之一

前三次调用会正确跟踪xBefore和yBefore值。然而,最后一次撤消调用只返回所有0值,并且到目前为止还没有跟踪状态。我假设每次初始化操作= PerformOperatio(..)..创建一组新动作?

如何使用闭包正确实现基本撤消逻辑?

2 个答案:

答案 0 :(得分:1)

每次调用声明了这些局部变量的方法时,闭包捕获的局部变量都会被有效地重新创建。你拥有的例子注定要失败,因为你只返回一个捕获了这些局部变量的最新实例的闭包。

在我看来,你应该做的是让方法本身执行操作,然后让方法返回{em>撤消刚刚完成的操作的Action委托

例如,像这样:

Action PerformOperation(int x1, int y1)
{
    int xBefore = x, yBefore = y;

    x = x1; y = y1;

    return () => { x = xBefore; y = yBefore; };
}

如果没有更完整的代码示例,我无法更具体。但我认为上面的内容更接近您对代码的期望。

然后,当您想要执行操作时,您可以调用该方法,并且当您想要撤消操作时,您将调用Action代理执行操作时由方法返回的内容。

多级撤消/重做接口需要比上面更精细的处理,但它仍然基于相同的基本思想:捕获变量有多个实例,每次都有一个每个变量的实例该方法被称为。

答案 1 :(得分:1)

实际上,您可以略微更改代码,并将xBeforeyBeforePerformOperation移出。我认为它按预期工作。因此,当前值和旧值都在operationUndooperationMove

的封闭内
int x = 0;
int y = 0;
int xBefore = 0;
int yBefore = 0; 

Action PerformOperation(bool move, bool undo, int x1, int y1)
{
    Action operationMove = null;
    Action operationUndo = null;


    operationMove = () => ...