Implementing a command template using a C # Action delegate

Is it possible to implement a GOF command template using Queue of Action delegates?

I'm trying to circle around myself for a while, and I'm at a standstill, because for each of the possible actions that I want to add to the queue, the number of parameters can be changed.

Any suggestions? Am I barking the wrong tree, focusing on the team pattern?

UPDATE:

Thanks a lot jgauffin, this works ... my implementation now looks like

public class CommandDispatcher { private readonly Dictionary<Type, List<Action<ICommand>>> _registeredCommands = new Dictionary<Type, List<Action<ICommand>>>(); public void RegisterCommand<T>(Action<ICommand> action) where T : ICommand { if (_registeredCommands.ContainsKey(typeof (T))) _registeredCommands[typeof (T)].Add(action); else _registeredCommands.Add(typeof (T), new List<Action<ICommand>> {action}); } public void Trigger<T>(T command) where T : ICommand { if (!_registeredCommands.ContainsKey(typeof(T))) throw new InvalidOperationException("There are no subscribers for that command"); foreach (var registeredCommand in _registeredCommands[typeof(T)]) { registeredCommand(command); if (command.Cancel) break; } } } 
+7
c # design-patterns command-pattern delegates
source share
3 answers

You can use the action. You should not use multiple parameters. What happens if a team needs a new parameter? Then you will need to change all the places that invoke the command plus the handler.

Instead, you should use command classes that have all parameters as properties. Thus, you can add parameters without affecting the code (new parameters should be considered as additional in the handler).

here's how i do it:

 public interface ICommand { // Cancel processing, do not invoke any more handlers public bool Cancel { get; set; } } public class CommandDispatcher { private Dictionary<Type, List<Action<ICommand>>> _commands = new Dictionary<Type, List<Action<ICommand>>>(); // Add to dictionary here public void Subscribe<T>(Action<T> action) where T : ICommand { List<Action<ICommand>> subscribers; if (!_commands.TryGetValue(typeof(T), out subscribers)) { subscribers = new List<Action<ICommand>>(); _commands.Add(typeof(T), subscribers)); } subscribers.Add(action); } // find command and to foreach to execute the actions public void Trigger<T>(T command) where T : ICommand { List<Action<ICommand>> subscribers; if (!_commands.TryGetValue(typeof(T), out subscribers)) throw new InvalidOperationException("There are no subscribers for that command"); foreach(var subsriber in subscribers) { subscriber(command); if (command.Cancel) break; //a handler canceled the command to prevent others from processing it. } } } public class AddTextCommand : ICommand { public string TextToAdd {get;set;} } public class TextHandler { public TextHandler(CommandDispatcher dispatcher) { disptacher.Subscribe<AddTextCommand>(OnAddText); } public void OnAddText(AddTextCommand cmd) { //.... } } public partial class MyForm : Form { CommandDispatcher _dispatcher; private void MyTextBox_Changed(object source, EventArgs e) { _dispatcher.Trigger(new AddTextCommand{TextToAdd = MyTextBox.Text}=; } } 

Note that the code is a kind of pseudo code. I wrote this directly in the answer without testing it. You may have to modify the material to make it work, but it should at least give you a hint. The implementation allows you to add multiple subscribers for each team.

+10
source share

In a command template, a typical command interface will have a simple execution method - this can be represented by an Action delegate. But the actual implementation will be provided by various specific classes, where you / can pass parameters (for example, through the constructor). For example:

 public interface ICommand { public void Execute(); } public class Command1 : ICommand { public Command1(int param1, string param2) { } ... } public class Command2 : ICommand { ... } public class Program { public static void Main() { ... var commands = new List<Action>(); commands.Add((new Command1(3, "Hello")).Execute); commands.Add((new Command2(...)).Execute); ... } } 

The point here is that the state and implementation associated with the team will be encapsulated in another implementation, while the Action delegate will point to its instance method. Therefore, calling the delegate will lead to the execution of the command.

+3
source share

If you are interested in the number of parameters, the correct implementation of the command template using the class will be the correct way. The Action delegate is limited to only one. Also, if you use an Action delegate, you may want to implement Undo later, which you cannot do with, since you just used a delegate instead of a class.

+1
source share

All Articles