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

本文关键字:重做 撤消 闭包 | 更新日期: 2023-09-27 17:57:53

我正在努力掌握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以类似的方式调用,然后最终返回两个操作之一

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

那么,我如何才能用闭包正确地实现基本的撤消逻辑呢?

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

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

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

例如,类似这样的东西:

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

如果没有一个更完整的代码示例,我就不能更具体了。但我认为以上内容更符合您对代码的期望。

然后,当您想执行操作时,您调用该方法,当您想要撤消该操作时,调用该方法在操作时返回的Action委托。

多级undo/redo接口需要比上面更精细的处理,但它仍然基于相同的基本思想:捕获的变量有多个实例,每次调用方法时每个变量都有一个实例。

实际上,您可以稍微更改代码,将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 = () => ...