Command Pattern in C#: Definition, Examples, Pros, Cons, and Use Cases
The Command pattern in C# is a behavioral design pattern that encapsulates a request or operation as an object, allowing parameterization, queuing, logging, and undoable operations.
The Command pattern converts requests into standalone command objects that contain all information needed to execute an action. It separates the object that invokes an operation from the object that performs it. A command object usually contains a reference to a receiver object and a method that executes the request. This pattern supports flexible operation management such as undo/redo, task scheduling, transaction handling, and command queues. In C#, the Command pattern is widely used in GUI applications, background job systems, menu systems, workflow engines, and CQRS architectures.
Why We Use Command Pattern in C#?
We use the Command pattern in C# to:
• Encapsulate operations into objects
• Decouple senders from receivers
• Support undo/redo functionality
• Enable command queues
• Allow delayed execution
• Simplify logging and auditing
• Improve extensibility
• Support transactional operations
When Should We Use Command Pattern in C#?
The Command pattern should be used when:
• Operations need to be parameterized
• Undo/redo functionality is required
• Commands should be queued or scheduled
• Request senders should not know execution details
• Multiple operations should share a common interface
• Actions need logging or auditing
• Macro or batch operations are required
Common Programming Problems Solved by Command Pattern
• Undo/redo systems
• Task queues
• Background job processing
• GUI button actions
• Macro recording systems
• Transaction processing
• Event-driven systems
• CQRS command handling
• Workflow execution systems
Structure of Command Pattern in C#
Typical participants:
• Command Interface
• Concrete Command
• Receiver
• Invoker
• Client
Basic workflow:
• Client creates command object
• Command stores receiver reference
• Invoker triggers command execution
• Receiver performs actual operation
Command Pattern Examples in C#
Example 1: Remote Control System
A remote control should trigger different device actions without knowing implementation details.
using System;
public interface ICommand
{
void Execute();
}
public class Light
{
public void TurnOn()
{
Console.WriteLine("Light is ON");
}
}
public class LightOnCommand : ICommand
{
private Light light;
public LightOnCommand(Light light)
{
this.light = light;
}
public void Execute()
{
light.TurnOn();
}
}
public class RemoteControl
{
private ICommand command;
public void SetCommand(ICommand command)
{
this.command = command;
}
public void PressButton()
{
command.Execute();
}
}
public class Program
{
public static void Main()
{
Light light = new Light();
ICommand lightCommand = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.SetCommand(lightCommand);
remote.PressButton();
}
}
Example 2: Undo/Redo Text Editor
A text editor should support undo functionality.
using System;
using System.Collections.Generic;
public interface ICommand
{
void Execute();
void Undo();
}
public class TextEditor
{
public string Text { get; private set; } = "";
public void Write(string value)
{
Text += value;
}
public void Erase(string value)
{
if (Text.EndsWith(value))
{
Text = Text.Substring(0, Text.Length - value.Length);
}
}
}
public class WriteCommand : ICommand
{
private TextEditor editor;
private string text;
public WriteCommand(TextEditor editor, string text)
{
this.editor = editor;
this.text = text;
}
public void Execute()
{
editor.Write(text);
}
public void Undo()
{
editor.Erase(text);
}
}
public class Program
{
public static void Main()
{
TextEditor editor = new TextEditor();
ICommand command = new WriteCommand(editor, "Hello");
command.Execute();
Console.WriteLine(editor.Text);
command.Undo();
Console.WriteLine(editor.Text);
}
}
Example 3: Job Queue System
Tasks should be queued and executed later.
using System;
using System.Collections.Generic;
public interface ICommand
{
void Execute();
}
public class EmailService
{
public void SendEmail()
{
Console.WriteLine("Email sent");
}
}
public class EmailCommand : ICommand
{
private EmailService service;
public EmailCommand(EmailService service)
{
this.service = service;
}
public void Execute()
{
service.SendEmail();
}
}
public class JobQueue
{
private Queue<ICommand> commands = new Queue<ICommand>();
public void AddJob(ICommand command)
{
commands.Enqueue(command);
}
public void ProcessJobs()
{
while (commands.Count > 0)
{
ICommand command = commands.Dequeue();
command.Execute();
}
}
}
public class Program
{
public static void Main()
{
EmailService service = new EmailService();
JobQueue queue = new JobQueue();
queue.AddJob(new EmailCommand(service));
queue.ProcessJobs();
}
}
Most Known Real-World Use Cases in C#
• Undo/redo systems
• GUI menu and button actions
• Background task queues
• Workflow engines
• CQRS command handling
• Macro recording systems
• Transaction processing
• Job schedulers
• Event sourcing systems
Advantages of Command Pattern in C#
• Decouples sender and receiver
• Supports undo/redo operations
• Enables command queuing
• Simplifies logging and auditing
• Supports delayed execution
• Improves extensibility
• Encourages Single Responsibility Principle
• Makes macro operations easier
Disadvantages (Weak Points) of Command Pattern in C#
• Increases number of classes
• Adds architectural complexity
• Simple operations may become over-engineered
• Undo logic can become difficult
• Command history may consume memory
• Debugging command chains can be harder
• May introduce additional abstraction overhead
Comparison with Similar Patterns
| Pattern | Main Purpose | Encapsulation Type | Execution Style | Typical Usage | Main Difference from Command |
|---|---|---|---|---|---|
| Command | Encapsulate requests as objects | Operations | Triggered by invoker | Undo systems, queues | Focuses on request encapsulation and execution |
| Strategy | Switch algorithms dynamically | Algorithms | Direct execution | Sorting, pricing | Encapsulates algorithms instead of executable requests |
| Memento | Save and restore state | Object state | Snapshot restoration | Undo/redo systems | Stores state snapshots instead of executable operations |
| Chain of Responsibility | Pass requests through handlers | Request processing | Sequential chain | Middleware pipelines | Passes requests through handlers instead of encapsulating actions |
| Mediator | Centralize communication | Object interactions | Through mediator | UI coordination | Coordinates communication instead of encapsulating operations |
Simplified UML-Style Structure
| Component | Responsibility |
|---|---|
| Command Interface | Defines execute operation |
| ConcreteCommand | Implements request execution |
| Receiver | Performs actual business operation |
| Invoker | Triggers command execution |
| Client | Creates and configures commands |
Creational Patterns in C#
13. Chain of Responsibility
14. Iterator
15. Momento
16. State
17. Template Method
18. Command
19. Mediator
20. Observer
21. Strategy
22. Visitor