Реализация отмены / повтора с использованием MemberwiseClone - PullRequest
4 голосов
/ 01 июля 2010

Я пытаюсь реализовать стек Undo / Redo в приложении C #, над которым я работаю, восстанавливая Object до предыдущего состояния при вызове undo.У меня есть класс 'Action', который выглядит в основном так:

class Action
{
    object old_state;
    object new_state;

    public Action(object old)
    {
        old_state = old;
    }

    public void finish(object new_obj)
    {
        new_state = new_obj;
    }

    public void reverse()
    {
        new_state = old_state;
    }
}

Когда запускается действие, которое может быть переделано, создается новое действие.Когда мы достигаем нового состояния, вызывается метод finish ().Когда пользователь хочет что-то повторить, он вызывает reverse () и восстанавливает объект в исходное состояние.

Очевидно, что это не работает, поскольку оба объекта передаются по ссылке, и объект просто заканчивается в новомгосударство.

Что я действительно хочу сделать, так это сказать:

public Action(object old)
{
    old_state = old.MemberwiseClone();
}

к сожалению, это не работает, и я получаю ошибку, которая выглядит следующим образом:

Невозможно получить доступ к защищенному члену 'object.MemberwiseClone ()' через спецификатор типа 'foo.object'

Я хочу создать поверхностную копию исходного состояния (скопировать всезначения полей по значению и все ссылочные поля по ссылке), но я не могу понять, как это сделать, используя универсальные объекты, в отличие от реализации IClonable в каждом классе, который я мог бы хотеть восстановить состояние.

Может ли кто-нибудь предложить какое-либо понимание?

Ответы [ 2 ]

2 голосов
/ 01 июля 2010

Вы можете использовать эту версию клонирования объекта (Примечание: объект должен быть сериализуемым, чтобы использовать эту функцию):

  /// <summary>
  /// Clones Any Object.
  /// </summary>
  /// <param name="objectToClone">The object to clone.</param>
  /// <return>The Clone</returns>
  public static T Clone<T>(T objectToClone)
  {
     T cloned_obj = default(T);
     if ((!Object.ReferenceEquals(objectToClone, null)) && (typeof(T).IsSerializable))
     {
        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bin_formatter = null;
        Byte[] obj_bytes = null;

        using (MemoryStream memory_stream = new MemoryStream(1000))
        {
           bin_formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
           try
           {
              bin_formatter.Serialize(memory_stream, objectToClone);
           }
           catch (Exception) { }
           obj_bytes = memory_stream.ToArray();
        }

        using (MemoryStream memory_stream = new MemoryStream(obj_bytes))
        {
           try
           {
              cloned_obj = (T)bin_formatter.Deserialize(memory_stream);
           }
           catch (Exception) { }
        }
     }
     return cloned_obj;
  }
0 голосов
/ 03 июня 2015

Чтобы добавить немного больше понимания этой проблемы ... Я заметил, что вы не можете использовать ссылку на экземпляр для вызова метода (потому что MemberwiseClone () определяется с идентификатором защищенной области).Вместо этого вы должны использовать ключевое слово this.

Для приведенного выше примера вам нужно будет сделать:

public Action(object old)
{
    old_state = this.MemberwiseClone();
}
...