mardi 5 décembre 2017

How about doing Command Pattern likes that in C#?

I am trying to support undo/redo for my application.

Then, I make it likes that, but I am not sure it is good practice.

interface ICommand
{
    string Description{get;}
    void Execute();
    void Undo();
}
class Command<T> : ICommand
{
    string m_actionDesc = string.empty;
    T m_target;
    Action<T> m_execute;
    Action<T> m_undo;
    public Command(T target, Action<T> execute, Action<T> undo)
    {
        m_target = target;
        m_execute = execute;
        m_undo = undo;
    }

    public string ActionDesc
    {
        get { return m_actionDesc; }
        set { m_actionDesc = value; }
    }

    #region ICommand members

    public string Description
    {
        get { return m_actionDesc; }
    }

    public void Execute()
    {
        m_execute(m_target);
    }

    public void Undo()
    {
        m_undo(m_target);
    }

    #endregion
}

Then, use them like that:

class LayerAction
{
    //contains List<Layer>, Layer with string Name{get;set;}
    LayerCollection m_layerCollection = new LayerCollection();
    //contains LinkedList<ICommand>, and with public Add(ICommand) method to add cmd to list
    CommandHistory m_history = new CommandHistory();

    public void ReName(int index, string name)
    {
        string oldname = m_layerCollection[index].Name;
        var cmd = new Command<DataLayer>(
            m_layerCollection[index],
            layer => layer.Name = name,
            layer => layer.Name = oldname)
        {
            ActionDesc = "Rename"
        };
        m_history.AddCommand(cmd);
        cmd.Execute();
    }
}

I have tested it, and it worked well. but, I'm confused that:

  1. the lambda can always work as my expected that auto generate class by C# closure effect? If there are some traps, I need to pay attention to it?

  2. the m_target argument can reduce the numbers of compiler generate class which no need to capture local variable?

========== if not use closure, i have to write many boring classes like that:

class LayerReNameCommand : ICommand
{
    Layer m_targetLayer;
    string m_oldname;
    string m_newname;
}

Aucun commentaire:

Enregistrer un commentaire