Простая и гибкая система отмены повторов - PullRequest
1 голос
/ 13 января 2020

Так что в основном я думал о системе отмены повторов (я слышал достаточно о шаблоне memmento и шаблоне команд, и я просто собираюсь REEEEEEEEEE), где вы сделаете объект этого класса UndoRedo внутри любого класса, который требует система UR, а затем каждая функция, которая может быть отменена, будет начинаться с генерации строки кода, которая отменяет действие (принимая во внимание такие вещи, как параметры, переданные функции и любую другую связанную информацию) и pu sh ее отмену стек URobject, который будет обрабатывать 2 стека надлежащим образом и иметь функции для удаления и повторения, которые просто извлекают код и оценивают его

Затем я нашел этот SO пост о том, как выполнить Eval в c# но это бесполезно, потому что это песочница, и мне нужен код Eval-ed для связи с остальным моим кодом и прочим.

Затем, с предложением @ CodeCharmander и разъяснением @ Fixation и небольшим количеством исследования я удалось заставить его работать!

Для всех, кто заинтересован в финальной кла ss:

using System;
using System.Collections.Generic;

class UndoRedo
{
    public Stack<Action> UndoStack { get; } = new Stack<Action>();
    public Stack<Action> RedoStack { get; } = new Stack<Action>();
    public Stack<Action> DoStack { get; } = new Stack<Action>();
    public Stack<Action> BackupStack { get; } = new Stack<Action>();


    public void Do(Action DoAct, Action UndoAct, bool Entry)
    {
        if ( Entry )
        {
            DoStack.Push( DoAct );
            UndoStack.Push( UndoAct );
            RedoStack.Clear();
            BackupStack.Clear();
        }
        DoAct();
    }

    public void Undo() 
    {
        var undoAct = UndoStack.Pop();
        undoAct();
        BackupStack.Push( undoAct );
        RedoStack.Push( DoStack.Pop() );
    }

    public void Redo()
    {
        var redoAct = RedoStack.Pop();
        redoAct();
        DoStack.Push( redoAct );
        UndoStack.Push( BackupStack.Pop() );
    }
}

Информация:

Функция Do принимает 2 лямбда-выражения в качестве делегатов. (Спасибо @CodeCharmander за предложение, @Fixation за разъяснение и Google за напоминание, как работают делегаты)

() => { //Code here }

Параметр Entry предназначен для случаев, когда действие Undo является вызовом любой другой отменяемой функции метод, он обычно должен быть установлен на основе того, какой объект / класс / метод вызвал другой отменяемый метод; Если это не установлено правильно, это может вызвать проблемы, при которых отмена действия добавляет упомянутое «отмена» как другое действие, создавая бесконечное l oop и очищая стеки Redo / Backup, когда это не должно

1 Ответ

3 голосов
/ 13 января 2020

Я думаю, CoderCharmander предлагает вам добавить делегатов в стек отмены вместо оценки C# скрипта. Вы можете вытолкнуть стек и просто выполнить делегат, когда будете готовы к отмене

    public Stack<Action> UndoStack { get; } = new Stack<Action>();
    public int Volatile { get; set; }

    public void Add(int i)
    {
        Volatile += i;
        UndoStack.Push(() => { Subtract(i); });
    }
    public void Subtract(int i)
    {
        Volatile -= i;
        UndoStack.Push(() => { Add(i); });
    }

    public void Undo()
    {
        var undoAction = UndoStack.Pop();
        undoAction();
    }
...