Memento vs State Pattern in C#: Key Differences Explained
Both the memento pattern and the state pattern are behavioral design patterns from the Gang of Four catalog, and both deal with how objects manage state. But the similarity ends there. When you examine the memento vs state pattern in C# closely, you find two fundamentally different approaches -- one captures and restores snapshots of an object's data, while the other changes an object's behavior based on its current lifecycle phase. Confusing them leads to designs that solve the wrong problem.
In this article, we'll break down each pattern's core purpose, walk through side-by-side C# code examples using a document editor scenario, and provide clear criteria for deciding between these two approaches. We'll also explore combining them, performance and complexity trade-offs, and a detailed FAQ section. If you want to go deeper on the state pattern or understand how the command pattern fits into the picture, those dedicated guides cover each individually.
Quick Overview: Memento and State Foundations
Before diving into the memento vs state pattern comparison, let's establish what each pattern does on its own.
The Memento Pattern
The memento pattern captures an object's internal state at a specific point in time so that the object can be restored to that state later. It involves three participants: the originator (the object whose state is saved), the snapshot object (the memento itself), and the caretaker (the object that stores and manages snapshots).
The defining characteristic is preservation without exposure. The originator creates a snapshot containing its private state, and the caretaker holds onto it -- but the caretaker never inspects or modifies the snapshot's contents. This keeps encapsulation intact while enabling undo, history, and rollback features.
The State Pattern
The state pattern allows an object to change its behavior when its internal state changes. The context delegates behavior to a current state object. When conditions change, the context swaps its state object for a different one, and subsequent method calls produce different results.
The defining characteristic is polymorphic behavior. Each state class implements the same interface, but handles method calls differently. State objects themselves drive transitions -- they know which states they can move to and under what conditions. The context doesn't contain conditional logic to determine behavior; it simply delegates to whatever state is active at that moment.
Side-by-Side Memento vs State Comparison
Here's a direct comparison of the memento vs state pattern across the dimensions that matter most in practice.
Intent: Snapshots vs Behavior Changes
The memento pattern's intent is to capture and restore state data. When you save a document, checkpoint a game, or record a transaction for potential rollback, this approach stores the object's data so you can travel back in time. The object's behavior doesn't change -- its data does.
The state pattern's intent is to change behavior based on the current lifecycle phase. When a document moves from Draft to PendingReview, the same Edit() call produces different behavior. The data may or may not change, but the behavioral response to the same operation shifts entirely. This intent distinction sits at the core of the memento vs state pattern difference.
State Handling: Capturing History vs Defining Transitions
The memento pattern is backward-looking. It records where the object has been so you can get back there. Each snapshot is a frozen copy that the originator can use to revert. The caretaker often maintains an ordered collection of these snapshots, forming a complete history. This makes undo/redo stacks straightforward to implement.
The state pattern is forward-looking. It defines where the object can go next. Each state object contains transition logic that moves the context to a new phase based on domain rules. There's no built-in concept of history -- once the context transitions from Draft to PendingReview, the Draft phase is gone unless you explicitly recreate it. The contrast is especially visible here: one preserves the past, the other governs the future.
Who Manages State: Caretaker vs Context
With the memento approach, the caretaker manages the saved states. The originator creates snapshots and restores from them, but the caretaker decides when to save, how many snapshots to keep, and when to restore. This separation keeps the originator focused on its primary responsibilities while the caretaker handles the logistics of preservation.
With the state approach, the context delegates to the current state object, and state objects control transitions. The context doesn't decide which phase to enter -- the state implementations make that decision internally. External code interacts with the context through its public interface, unaware of the underlying machinery. This is similar in spirit to how the strategy pattern delegates to interchangeable implementations, though the key difference is that state objects drive their own transitions.
Encapsulation: Preserving vs Polymorphic Dispatch
The memento pattern focuses on data encapsulation. The snapshot stores private state without exposing it to the outside world. The caretaker holds a black box -- it can pass the snapshot back to the originator, but it cannot read or modify the contents. This is critical for maintaining the originator's encapsulation boundaries.
The behavioral side focuses on polymorphic encapsulation. Each state class encapsulates the behavior appropriate to that phase, replacing conditional logic with polymorphism. Rather than a giant switch block or nested if/else chains in the context, each class contains only the logic relevant to its phase.
C# Code Examples: Memento vs State for Document Editor
Let's make this comparison concrete with a real example. We'll build a document editor -- first using the memento approach for undo support, then using the state approach for workflow behavior -- so you can see how each pattern addresses a different concern in the same domain.
Memento Pattern Approach
With the memento pattern, the editor captures snapshots of its content so users can undo and redo changes. The editor is the originator, the snapshot is the memento, and a history manager acts as the caretaker:
// The memento -- stores a snapshot of editor state
public sealed class EditorMemento
{
public string Content { get; }
public int CursorPosition { get; }
public EditorMemento(
string content,
int cursorPosition)
{
Content = content;
CursorPosition = cursorPosition;
}
}
// The originator -- creates and restores from mementos
public sealed class DocumentEditor
{
public string Content { get; private set; } = string.Empty;
public int CursorPosition { get; private set; }
public void Type(string text)
{
Content = Content.Insert(CursorPosition, text);
CursorPosition += text.Length;
}
public void MoveCursor(int position)
{
CursorPosition = Math.Clamp(
position, 0, Content.Length);
}
public EditorMemento Save()
{
return new EditorMemento(
Content, CursorPosition);
}
public void Restore(EditorMemento memento)
{
Content = memento.Content;
CursorPosition = memento.CursorPosition;
}
}
The caretaker manages the undo/redo stacks:
// The caretaker -- manages memento history
public sealed class EditorHistory
{
private readonly Stack<EditorMemento> _undoStack = new();
private readonly Stack<EditorMemento> _redoStack = new();
public void SaveState(EditorMemento memento)
{
_undoStack.Push(memento);
_redoStack.Clear();
}
public EditorMemento? Undo()
{
return _undoStack.Count > 0
? _undoStack.Pop()
: null;
}
public void SaveForRedo(EditorMemento memento)
{
_redoStack.Push(memento);
}
public EditorMemento? Redo()
{
return _redoStack.Count > 0
? _redoStack.Pop()
: null;
}
}
Usage demonstrates the memento pattern's core value -- traveling backward and forward through state history:
var editor = new DocumentEditor();
var history = new EditorHistory();
// Save initial state, then type
history.SaveState(editor.Save());
editor.Type("Hello ");
// Save again, then type more
history.SaveState(editor.Save());
editor.Type("World");
Console.WriteLine(editor.Content);
// Output: "Hello World"
// Undo to previous state
var previous = history.Undo();
if (previous is not null)
{
history.SaveForRedo(editor.Save());
editor.Restore(previous);
}
Console.WriteLine(editor.Content);
// Output: "Hello "
Notice that the memento approach doesn't change what Type() or MoveCursor() does. Those methods always behave the same way. The pattern only captures and restores data -- it's purely about preservation. This is one of the clearest memento vs state pattern distinctions you can observe in practice.
State Pattern Approach
Now let's solve a different concern in the same document editor using the state pattern. Instead of undo/redo, we'll model workflow behavior -- the editor responds differently to the same actions depending on whether the document is in Draft, Review, or Locked mode:
public interface IEditorState
{
void Type(EditorContext context, string text);
void Submit(EditorContext context);
void Lock(EditorContext context);
string GetMode();
}
public sealed class EditorContext
{
public IEditorState CurrentState { get; private set; }
public string Content { get; set; } = string.Empty;
public EditorContext()
{
CurrentState = new DraftMode();
}
public void SetState(IEditorState state)
{
CurrentState = state;
Console.WriteLine($"Mode changed to: {state.GetMode()}");
}
public void Type(string text) =>
CurrentState.Type(this, text);
public void Submit() =>
CurrentState.Submit(this);
public void Lock() =>
CurrentState.Lock(this);
}
Each state class encapsulates behavior specific to that workflow phase:
public sealed class DraftMode : IEditorState
{
public void Type(EditorContext context, string text)
{
context.Content += text;
Console.WriteLine($"Typed: {text}");
}
public void Submit(EditorContext context)
{
Console.WriteLine("Submitting for review...");
context.SetState(new ReviewMode());
}
public void Lock(EditorContext context)
{
Console.WriteLine("Cannot lock a draft.");
}
public string GetMode() => "Draft";
}
public sealed class ReviewMode : IEditorState
{
public void Type(EditorContext context, string text)
{
Console.WriteLine(
"Cannot type while in review.");
}
public void Submit(EditorContext context)
{
Console.WriteLine("Already in review.");
}
public void Lock(EditorContext context)
{
Console.WriteLine("Approving and locking...");
context.SetState(new LockedMode());
}
public string GetMode() => "Review";
}
public sealed class LockedMode : IEditorState
{
public void Type(EditorContext context, string text)
{
Console.WriteLine(
"Cannot type -- document is locked.");
}
public void Submit(EditorContext context)
{
Console.WriteLine(
"Cannot submit -- document is locked.");
}
public void Lock(EditorContext context)
{
Console.WriteLine("Already locked.");
}
public string GetMode() => "Locked";
}
Usage shows how the state pattern changes behavior as the editor transitions through modes:
var context = new EditorContext();
context.Type("Draft content");
// Output: "Typed: Draft content"
context.Submit();
// Output: "Submitting for review..."
// Output: "Mode changed to: Review"
context.Type("More content");
// Output: "Cannot type while in review."
context.Lock();
// Output: "Approving and locking..."
// Output: "Mode changed to: Locked"
The same Type() call produces completely different behavior depending on the current state. In Draft mode, it appends text. In Review mode, it refuses. In Locked mode, it refuses with a different message. Compare this to the memento approach where Type() always appends text regardless of context. The difference here is behavior consistency versus behavior variation.
Combining Memento and State Patterns
The memento vs state pattern comparison doesn't have to be either-or. These two patterns solve orthogonal problems, and they combine naturally when you need both workflow behavior and undo capability.
Consider a document editor where the state pattern controls what operations are valid in each workflow phase, and the memento approach captures snapshots so users can roll back changes within the Draft phase:
public sealed class DraftModeWithUndo : IEditorState
{
private readonly EditorHistory _history;
public DraftModeWithUndo(EditorHistory history)
{
_history = history;
}
public void Type(EditorContext context, string text)
{
// Capture a memento before modifying
_history.SaveState(
new EditorMemento(context.Content, 0));
context.Content += text;
Console.WriteLine($"Typed: {text}");
}
public void Submit(EditorContext context)
{
Console.WriteLine("Submitting for review...");
context.SetState(new ReviewMode());
}
public void Lock(EditorContext context)
{
Console.WriteLine("Cannot lock a draft.");
}
public string GetMode() => "Draft (with undo)";
}
In this combined design, the state pattern determines whether typing is allowed, and the snapshot mechanism preserves history so the user can undo within that phase. Each pattern handles a different axis of concern. One governs transitions and behavior rules. The other governs history and rollback. Together, they provide a richer model than either achieves alone.
This combination also pairs well with the command pattern. You can wrap each user action in a command object, have the command save a snapshot before executing, and let the state pattern control which commands are valid in each phase. This three-pattern composition is common in editor and IDE architectures where undo support intersects with workflow rules.
Performance and Complexity Trade-Offs
Understanding the memento vs state pattern trade-offs helps you avoid over-engineering or under-engineering your solution.
Memento memory overhead. Every snapshot captures the originator's full state and consumes memory. For lightweight objects, this is negligible. But for objects with large state -- think image editors, rich text documents, or complex game worlds -- storing full copies on every change becomes expensive. Consider limiting the undo stack depth, using incremental snapshots that store only what changed, or compressing data for large objects.
State class proliferation. This behavioral pattern requires a separate class for each state. If your workflow has three states, that's manageable. If it has fifteen, you now have fifteen classes implementing the same interface. This doesn't affect runtime performance, but it increases codebase size and cognitive load. If your transitions are simple, an enum-based approach might be more practical.
Memento serialization costs. When snapshots need to persist beyond the current session -- for crash recovery, audit trails, or collaborative editing -- you'll need to serialize them. Deep object graphs with circular references make serialization non-trivial. Plan your snapshot's data structure with serialization in mind from the start.
Transition validation. As the number of states grows, ensuring that all transitions are valid becomes harder. Missing a transition case can lead to invalid combinations. Consider supplementing with the observer pattern to log and monitor transitions, or write explicit tests covering each transition path.
Combining adds integration complexity. When you use both patterns together, each snapshot must capture enough data to restore the object accurately, and the behavioral side must remain consistent after a restore. If undo reverts the data but the active state object isn't reverted, the system ends up in an inconsistent position. Make sure your snapshots capture the current state type alongside the data.
Decision Criteria: Memento vs State Pattern
When deciding between the memento vs state pattern, consider these questions:
Do you need undo, redo, or rollback? If yes, the memento pattern is the right choice. It's purpose-built for capturing and restoring snapshots. The behavioral state approach doesn't provide history management out of the box.
Does the same method call need to produce different behavior at different times? If yes, use the state pattern. When Submit() should do different things depending on whether the document is in Draft, Review, or Locked mode, polymorphic state objects encapsulate that behavioral variation cleanly.
Are you tracking history or governing transitions? The memento approach records the past. The state approach governs the present and defines valid paths to the future. If you need to answer "where was this object five steps ago," that's a snapshot concern. If you need to answer "what can this object do in its present state," that's a behavioral concern.
Do state objects need to manage their own lifecycle transitions? If the object moves between phases automatically based on domain rules, the state pattern fits. If external code is just saving and restoring data, the memento fits.
Do you need both? If your system has workflow behavior and rollback requirements, combine them. Use the state pattern for behavioral governance and the memento for history preservation.
Common Memento vs State Mistakes
Developers make several recurring mistakes when implementing or choosing between these two patterns.
Exposing snapshot internals. The whole point of the memento pattern is to preserve encapsulation. If your caretaker reads or modifies snapshot contents, you've broken the contract. In C#, use access modifiers or nested classes to restrict access to the originator.
Forgetting to capture state type in snapshots. When combining both patterns, restoring the originator's data without restoring its current state object leaves the system inconsistent. Always include the state type or identifier in the snapshot.
Building state objects that never transition. If your state implementations never call context.SetState(), they're functionally just strategies. States must drive transitions -- that's what distinguishes the state pattern from the strategy pattern.
Using snapshots for behavioral changes. If you find yourself restoring a memento and then checking the restored data to decide how the object should behave, you're mixing concerns. Let the state pattern handle behavioral variation. The memento should only handle data preservation.
Ignoring memory pressure with snapshots. Keeping an unbounded undo stack for objects with large state leads to memory issues. Set a maximum history depth and discard the oldest entries when the limit is reached. You could also leverage the iterator pattern to traverse history without loading every snapshot into memory at once.
Comparison Summary Table
Here's a quick-reference table summarizing the memento vs state pattern differences:
| Feature | Memento | State |
|---|---|---|
| Intent | Capture and restore state snapshots | Change behavior based on current state |
| Focus | Data preservation | Behavioral variation |
| Direction | Backward-looking (history) | Forward-looking (transitions) |
| Participants | Originator, Memento, Caretaker | Context, State interface, Concrete states |
| Encapsulation | Protects internal data from exposure | Replaces conditionals with polymorphism |
| Transition control | None -- caretaker restores on demand | State objects drive transitions internally |
| History support | Built-in (undo/redo stacks) | No built-in history |
| Method behavior | Consistent regardless of state | Changes based on current state |
| Memory impact | Grows with number of snapshots | Constant (one active state object) |
| Typical use cases | Undo/redo, checkpoints, rollback | Workflows, protocols, mode switching |
Both patterns deal with object state, but the distinction is clear: one is about remembering where you've been, and the other is about governing where you are.
Frequently Asked Questions
What is the main difference between the memento and state pattern in C#?
The memento pattern captures and restores an object's internal data as snapshots, enabling features like undo and rollback. The state pattern changes an object's behavior based on its current lifecycle phase by delegating to polymorphic state objects. One preserves data history while the other governs behavioral transitions. They solve fundamentally different problems even though both deal with "state."
Can the memento pattern replace the state pattern for managing workflows?
No. The snapshot approach records data but doesn't control behavior. Restoring a memento gives you old data, but it doesn't change how the object responds to method calls. If your editor needs to reject edits during a review phase, you need the state pattern's polymorphic behavior -- restoring to a "Draft" snapshot won't prevent the Type() method from executing. Use the state pattern for behavioral workflow governance and snapshots for data rollback.
When should I combine the memento and state patterns?
Combine them when your system needs both workflow-driven behavior and undo/redo capability. For example, a document editor where the state pattern controls what actions are valid in each workflow phase (Draft, Review, Locked) and the snapshot mechanism captures content for undo within each phase. Each pattern handles a separate concern, and they integrate cleanly when the snapshot includes the current state type alongside the data.
How does the memento pattern preserve encapsulation in C#?
The snapshot stores the originator's private state, but the caretaker that holds it never accesses the internals. In C#, you can enforce this by making the memento a nested class inside the originator with internal or private accessors, or by exposing only an opaque interface to the caretaker. This lets you save and restore state without leaking implementation details to the rest of the system.
Does the state pattern support undo functionality?
Not by itself. The state pattern replaces the current state object when a transition occurs, and the previous phase is discarded. There is no built-in mechanism to remember or revert to prior states. If you need undo alongside transitions, pair it with the memento pattern. You could also incorporate the command pattern to wrap each state-changing operation in a reversible command that saves a snapshot before executing.
What are the memory implications of the memento pattern?
Each snapshot is a copy of the originator's state at a point in time. For objects with small state -- a few strings and integers -- the memory cost is negligible. For objects with large state, such as image buffers or complex object graphs, unbounded snapshot stacks become expensive. Cap the history size, store incremental diffs instead of full copies, or compress data to manage memory usage effectively.
How do I choose between the memento and state pattern for a new C# project?
Start with the problem you're solving. If users need to undo actions, replay history, or roll back changes, reach for the memento pattern. If your object's behavior needs to change as it moves through defined lifecycle phases -- and invalid operations should be rejected based on the current phase -- use the state pattern. If you need both, combine them. Integrating these patterns with dependency injection through inversion of control containers makes both more testable and maintainable in production C# applications.
Wrapping Up Memento vs State Pattern in C#
The memento vs state pattern in C# distinction comes down to preservation versus governance. The memento captures and restores data snapshots, giving you undo, redo, and rollback. The state pattern changes behavior through polymorphic delegation, making the same method call produce different results depending on the current lifecycle phase.
When your system needs to remember where an object has been, use the memento. When your system needs to control what an object does based on where it is, use the state pattern. And when you need both -- history preservation alongside behavioral transitions -- combine them. Each addresses a different dimension of state management, and understanding which dimension you're working with is the key to choosing correctly.

