Прототипирование командного класса без сериализации - PullRequest
0 голосов
/ 12 января 2020

То, что я пытаюсь выполнить sh

Я создал простой API, в который я пытаюсь наложить несколько различных шаблонов. В частности, команда, составной и прототип. Это Prototype, с которым у меня проблемы. Невероятно сложно продублировать этот тип и сломать все предыдущие ссылки. Причина, по которой я sh создаю прототип этого класса, состоит в том, что Команды должны запускаться только один раз, но если вам нужно sh, чтобы повторить функциональность, было бы легко дублировать Команды.

Где я работаю перебои

Интерфейс ICommand, который реализован во всех типах этой библиотеки, имеет метод ICommand Duplicate (). Единственный метод успешно прототипирует и проходит этот тест.

        [Test]
        public void Duplicated_Commands_Should_Be_Equivalent_But_Not_Identitical()
        {
            var sut = new ActionCommand(
                callAction: _incrementTestValue,
                undoAction: _decrementTestValue,
                failureAction: _flagFailedTest);

            var protoCommand = sut.Duplicate();

            sut.Should().BeEquivalentTo(protoCommand); //Value equality.
            sut.Should().NotBeSameAs(protoCommand); //Referential equality.

Однако, когда я пытаюсь ProtoType CompositeCommand, который является как списком ICommands, так и самой ICommand, согласно шаблону Composite, я сталкиваюсь с проблемой .

        [Test]
        public void Duplicated_Commands_Should_Yield_Same_Result()
        {
            int testVal = 0;
            var sut = new CompositeCommand(
                new ActionCommand(() => testVal++, () => testVal--, WriteLineOnFailure),
                new ActionCommand(() => testVal++, () => testVal--, WriteLineOnFailure),
                new ActionCommand(() => testVal++, () => testVal--, WriteLineOnFailure),
                new ActionCommand(() => testVal++, () => testVal--, WriteLineOnFailure));

            sut.Call();

            testVal.Should().Be(sut.Count, "Each command increments this by one");

            sut.Call();

             testVal.Should().Be(sut.Count, "Assuming the previous Call() was successful the subsequent call should have exited early.");
sut.Success.Should().BeTrue();

            var protoCommand = sut.Duplicate();

//THE LINE BELOW THIS FAILS
            sut.Success.Should().BeTrue("Duplicating the sut should not mutate it in any way.");
//THE LINE ABOVE THIS FAILS

            sut.Success.Should().BeFalse("Duplicated commands should have their Success set to false so that they can be executed.");
            sut.Call();
            protoCommand.Call();

            testVal.Should().Be(sut.Count * 2, "We have 2 sets of identical commands.");

            protoCommand.Call();

            testVal.Should().Be(sut.Count * 2, "As with its singular counterpart, even duplicated commands should be Idempotent.");
        }

Использование метода ICommands Call () обычно устанавливает для свойства Success значение true. Как вы можете видеть, это верно до вызова Duplicate, и CompositeCommand имеет аналогичный [Test], который подтверждает, что он эквивалентен, но не идентичен продукту его метода Duplicate.

При прохождении через него с помощью отладчика это показывает, что свойство Success sut помечается обратно в false, как только первая Duplicate ICommand назначается списку команд CompositeCommands. Он обнаруживает, что новая команда, для которой в конструкторе установлено значение «Успешное значение false», определенное по умолчанию, имеет свойство «Успешно», равное false, а CompositeCommand показывает «Успешное значение true» только в том случае, если все ее Команд успешно выполнены с помощью этого метода:

        public bool Success
        {
            get
            {
                foreach (var command in Commands)
                {
                    if (command.Success is false) return false;
                }

                return true;
            }
            set
            {
                foreach (var command in Commands)
                {
                    command.Success = value;
                }
            }
        }

То, что я до сих пор пробовал

Я пытался традиционное прототипирование с использованием сериализации и либо двоичной, либо xml сериализации. Делегаты, которые содержит этот тип, плохо реагируют на сериализацию, делегаты либо возвращают ноль с сериализацией xml, либо выдают исключение, когда делегат ссылается на значение из другого типа, такого как делегат Call, являющийся AnotherClassValue ++.

Я пытался создать конструктор Deep Copy, по отдельности вызвав метод Duplicate каждой отдельной ICommand и добавив продукты этого нового CompositeCommand. Это работает нормально, пока конструктор не разрешит, установив false для оригинала и прототипа на false, что заставляет меня поверить, что ссылки на ICommands действительно не нарушаются, несмотря на использование нового ключевого слова.

Любые предложения относительно того, что я мог бы исследовать, чтобы обнаружить источник проблемы? Я открыт для изменений в моем дизайне или любых тестах, которые кто-либо может предложить. **

Наконец, я рассказал всем здесь о самих методах Duplicate.

Command.Duplicate ()

        public ICommand Duplicate()
        {
            var product = new ActionCommand(CallAction, UndoAction, FailureAction);
            return product;
        }

CompositeCommand.Duplicate ()

        public ICommand Duplicate()
        {
            var commands = new ICommand[Commands.Count];
            var currentCommands = Commands.ToArray();

            for (var i = 0; i < commands.Length; i++)
            {
                commands[i] = currentCommands[i].Duplicate();
            }

            return new CompositeCommand(commands);
        }
...