C # Отменить / Повторить с деревьями и потоками - PullRequest
1 голос
/ 21 марта 2012

Я искал несколько часов и не смог найти ничего похожего на этот вопрос, хотя я уверен, что это должно было быть сделано ранее: (

Пользователь сначала вводит комбинациючисел и знаков +/- Например: 5 + (7- (4 + 1) -3) + 11. У меня есть класс Add и класс Subtract, программа строит дерево из этих двух классов из входных данных.в этом примере дерево будет выглядеть примерно так:

Add: 5
     Subtract: 7
     11        Add: 4
               3    1

Теперь у каждого класса есть рекурсивный метод StepEvaluate, который сначала выводит на консоль всю сумму. Таким образом, для поддерева Subtract предыдущего примера этот объект будетвыведите «7 - (4 + 1) - 3». Затем он перечислит каждый узел дерева и попросит пользователя щелкнуть ветку, чтобы сложить / вычесть начальную сумму, равную 0. Это, наконец, напечатает ответ наконец. Таким образом, если мы возьмем 5 + (7-3) + 11, вывод на консоль будет:

5 + (7-3) + 11
We are going to add to the total with each choice.
The current total is 0.
Choose from the following:
5
+
7-3
+
11
You chose: 11
The current total is 11.
Choose from the following:
5
+
7-3
You chose: 7-3
    7 - 3
    We are going to subtract from the total with each choice.
    The current total is 0.
    Choose from the following:
    7
    -
    3
    You chose: -3
    The current total is -3.
    The only remaining choice is 7.
    The current total is 4.
    So the answer is 4.
The current total is 15.
The only remaining choice is 5.
The current total is 20.
So the answer is 20.

Теперь моя консоль представляет собой текстовое поле. В конструкторе формы новый поток, Eval, сделан для оценки и выводавышеуказанные результаты.Каждый раз, когда пользователь нажимает кнопку, он возобновляет поток Eval и приостанавливает текущий поток.Затем Eval обрабатывает следующую строку для вывода (используя описанные выше рекурсивные классы), записывает строку в статическую переменную, возобновляет выполнение основного потока и приостанавливает выполнение Eval.Затем основной поток читает эти статические переменные и выводит их в текстовое поле (производитель-потребитель).В промежутках между нажатиями кнопок вводимые пользователем данные записываются в статические переменные, поэтому Eval может прочитать их после возобновления.

Я хочу, чтобы в форме была еще одна кнопка, которая будет возвращаться на строку назад.Если это стирает строку «Вы выбрали А», то пользователь может изменить свой выбор, поэтому следующий вывод может быть «Вы выбрали В».

Я прочитал памятные и командные образцы и знаю ооснованный на состоянии и основанный на действии отмена / повтор.Однако я понятия не имею, как реализовать это с помощью приведенных выше потоков рекурсии и производителя / потребителя.Все, что мне действительно нужно, - это способ заставить точку исполнения Eval вернуться на линию.Но я почти уверен, что не смогу этого сделать ...

Если вам нужен код для сложения и вычитания, то вы идете:

class Add : MathsOperation
{
    public List<MathsOperation> Children;

    private int total;

    public override void StepEvaluate()
    {
        MathsOperation currentEvaluation;
        writeToConsole(this.ToString());

        List<MathsOperation> toBeEvaluated = new List<MathsOperation>(Children);

        writeToConsole("We are going to add to the total with each choice."); 


        while (toBeEvaluated.Count > 1)
        {
            writeToConsole("The current total is " + total + ".");
            writeToConsole("Please choose from the following:");
            string choices = "";
            foreach (MathsOperation child in toBeEvaluated)
            {
                choices += Environment.NewLine  + child.ToString();
                if (child != Children.Last())
                    choices += Environment.NewLine + "+";
            }
            writeToConsole(choices);

            currentEvaluation = read();

            if (currentEvaluation is Number)
            {
                //add to the total and write output
            }
            else
            {
                currentEvaluation.StepEvaluate();
                //add the static variable Result to the total and write output
            }

            toBeEvaluated.Remove(currentEvaluation);
        }

        currentEvaluation = toBeEvaluated.First();
        writeToConsole("The only remaining choice is " + currentEvaluation.ToString());

        if (currentEvaluation is Number)
        {
            //add to the total and write output
        }
        else
        {
            currentEvaluation.StepEvaluate();
            //add the static variable Result to the total and write output
        }

        toBeEvaluated.Remove(currentEvaluation);

        writeToConsole("So the answer is " + total.ToString());

        //write total to static variable Result

    }

    private void writeToConsole(string txt)
    {
        //Write to static variable, resume main thread and pause this one
    }
    private MathsOperation read()
    {
        //read the static variable. I have replaced this with return new for simplicity
        return new MathsOperation();
    }
}

Если у вас есть идеи,Я буду более чем счастлив принять их.

Спасибо заранее за вашу помощь.

1 Ответ

0 голосов
/ 14 июня 2012

Я бы использовал решение, подобное этому: Использовать среду отмены / повторения.Я нашел хороший вариант на CodeProject.В противном случае сохраняйте отмены и повторы как стеки, содержащие их собственные личные копии данных.

В стеке отмены выдвиньте все состояние (ваше дерево оценки вместе с другим необходимым состоянием).Убедитесь, что состояние не передается по ссылке, например, внедрите ICloneable.

Это было немного кратко, но надеюсь, это поможет.

...