Implementing undo/redo using MemberwiseClone
I'm trying to implement an Undo/Redo stack in a C# application that I'm working on by restoring an Object to a previous state when undo is called. I have an 'Action' class which looks basically like this:
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;
}
}
When an action is started that can be redone, a new action is created. When we reach the new state, finish() is called. When the user wants to redo something, it calls reverse() and restores the Object to its original state.
Obviously this doesn't work since both objects are passed by reference and the object just ends up in the new state.
What I really want to do is to be able to say:
publi开发者_如何学编程c Action(object old)
{
old_state = old.MemberwiseClone();
}
unfortunately, this doesn't work, and I get an error that looks like:
Cannot access protected member 'object.MemberwiseClone()' via a qualifier of type 'foo.object'
I want to create a shallow copy of the original state (copy all of the value fields by value and all of the reference fields by reference), but I can't figure out how to do this using generic objects, as opposed to implementing IClonable
in every class of which I could possibly wish to restore the state.
Can anyone offer any insight?
You could use this version of cloning an object (Note: The object must be serializable in order to use this function):
/// <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;
}
To add a little more insight to this issue... I've noticed that you can't use an instance reference to call the method (because MemberwiseClone() is defined with a protected scope identifier). Instead you have to use the this
keyword.
For the example given above you would have to do:
public Action(object old)
{
old_state = this.MemberwiseClone();
}
精彩评论