BrandGhost
When to Use State Pattern in C#: Decision Guide with Examples

When to Use State Pattern in C#: Decision Guide with Examples

When to Use State Pattern in C#: Decision Guide with Examples

Objects change behavior based on their internal condition all the time. A document goes from draft to review to published. A game character switches between idle, running, and attacking. A payment moves from pending to authorized to captured. The when to use state pattern in C# question comes up the moment your conditional logic starts branching on the same status field in method after method -- and every new state forces you to touch multiple files. That's the pain this pattern solves.

This article walks you through a practical decision framework for the state pattern in C#. You'll see when it genuinely earns its place and when simpler approaches like enums or boolean flags do the job just fine. We'll cover real code examples for complex conditional behavior, workflow management, game state management, UI component states, and document lifecycles. You'll also learn how the state pattern compares to the strategy pattern and other alternatives so you can make informed architectural decisions.

What the State Pattern Actually Does

The state pattern lets an object change its behavior when its internal state changes. From the outside, it looks like the object changed its class. Instead of scattering if and switch statements across every method that cares about the current state, you encapsulate each state's behavior in its own class. The object delegates to whichever state object is at that point active.

The structure involves three roles. A context holds a reference to the current state object and delegates behavior to it. A state interface declares the methods that each state must implement. And concrete state classes implement that interface with behavior specific to their state. When a transition happens, the context swaps its current state reference to a new state object.

This approach eliminates the sprawling conditional blocks that grow every time you add a new state. Instead of modifying existing methods, you create a new state class that implements the interface. The observer pattern notifies external subscribers about changes. The state pattern changes internal behavior. They can work together -- a state transition might raise events that observers handle -- but they solve different problems. You can even nest state-bearing objects within tree structures managed by the composite pattern, where each node in the hierarchy maintains its own independent state.

Signs You Need the State Pattern in C#

Not every object with a status field needs the state pattern. But certain code smells are strong signals that the pattern will clean up your design and make future changes easier.

Your Conditional Logic Branches on the Same State Variable Everywhere

This is the primary trigger. When you see the same switch or if-else chain checking _status in three, four, or ten different methods, your object is doing state-dependent branching the hard way. Every new state means touching every one of those methods. Every developer who adds a feature has to find and update all the branches. The state pattern eliminates this by giving each state its own class where all the relevant behavior lives in one place.

You Have Complex Transition Rules Between States

When the valid transitions between states follow specific rules -- a document can't jump from draft to published without going through review, a payment can't be refunded before being captured -- encoding those rules in scattered conditionals gets brittle fast. The state pattern lets each state class define which transitions it allows. An UnderReviewState knows it can transition to ApprovedState or RejectedState but not directly back to DraftState. The rules live where they belong.

Each State Has Distinct Behavior

If the behavior genuinely changes depending on the state -- a door responds differently to Open() when it's locked versus unlocked, a player character attacks differently when buffed versus debuffed -- the state pattern gives each behavior a clean home. Without it, every method that varies by state needs its own branching logic, and the behavioral differences get tangled together.

Your Object's States Keep Growing

Two or three states with simple transitions might not justify the pattern. But when your state count keeps climbing -- pending, processing, awaiting approval, approved, rejected, escalated, cancelled, completed -- each new state becomes progressively harder to add with conditional logic. The state pattern makes adding a new state a matter of creating one new class rather than hunting through every method for the right place to add another branch.

You Need State-Specific Validation

When the valid operations depend on the current state -- you can't cancel an order that's already shipped, you can't edit a published article -- each state class can enforce its own rules. Invalid operations throw exceptions or return error results from the state class itself, rather than being checked in a dozen different places across your codebase.

When NOT to Use the State Pattern

Knowing when to use the state pattern in C# is only half the picture. Reaching for it when simpler mechanisms work adds layers of indirection that make your code harder to read, navigate, and maintain.

Simple Boolean States

If your object has two states -- on/off, active/inactive, enabled/disabled -- a boolean field is the right tool. Creating ActiveState and InactiveState classes for a toggle adds a minimum of three new files (the interface plus two implementations) to replace what a single bool handles cleanly. The state pattern's value comes from managing complexity, not from creating it.

Few States with No Meaningful Transitions

When you have a handful of states and the transitions between them are trivial -- set a status, check a status -- the state pattern adds ceremony without benefit. If every method in every state does roughly the same thing with minor variations, you don't have genuinely distinct behaviors. You have a status field with cosmetic differences.

When Enums Suffice

An enum with a switch statement is a perfectly valid approach when your states are data-oriented rather than behavior-oriented. If you're primarily storing, displaying, and comparing states -- not executing different logic per state -- an enum is simpler, more discoverable, and more familiar to every C# developer. The state pattern solves behavioral variation, not categorical labeling.

When the Transition Logic Is External

If state transitions are driven entirely by external orchestration -- a workflow engine, a state machine library, or a message broker -- wrapping each state in its own class may duplicate what the orchestrator already handles. Evaluate whether the state pattern adds value beyond what your infrastructure provides.

Decision Framework for the State Pattern in C#

Walk through these questions when evaluating whether the state pattern fits your scenario. If most of them get a "yes," the pattern is likely worth the investment.

Does behavior change based on state? If the same method does fundamentally different things depending on the object's current condition, the state pattern gives you a clean way to organize those variations. If the behavior is consistent regardless of state, you don't need it.

Are you tired of editing the same switch statement? When every new state or behavioral change forces you to modify the same branching logic in multiple methods, the state pattern eliminates that repeated editing. Each state class encapsulates its own behavior.

Do transitions follow rules? If certain state transitions are invalid -- and enforcing those rules matters for correctness -- the state pattern lets each state define its own valid transitions. This is cleaner than a centralized transition validation method that grows with every new state.

Is the state count growing? Three states might not justify the pattern. Eight states almost certainly do. The overhead of one class per state is fixed, while the overhead of conditional branching grows combinatorially with states and methods.

Will multiple developers work on state-related code? The state pattern reduces merge conflicts and cognitive load when different developers add or modify different states. Each state is an isolated class rather than a branch buried inside a shared method. Registering state classes via dependency injection keeps the wiring clean and testable.

Scenario 1: Complex Conditional Behavior -- Order Processing

Consider an e-commerce order that behaves differently depending on its lifecycle stage. Without the state pattern, you'd have switch statements in every method:

public interface IOrderState
{
    void Submit(OrderContext context);
    void Cancel(OrderContext context);
    void Ship(OrderContext context);
    void Deliver(OrderContext context);
}

public sealed class OrderContext
{
    public IOrderState CurrentState { get; private set; }
    public string OrderId { get; }

    public OrderContext(string orderId)
    {
        OrderId = orderId;
        CurrentState = new PendingState();
    }

    public void TransitionTo(IOrderState state)
    {
        Console.WriteLine(
            $"Order {OrderId}: " +
            $"{CurrentState.GetType().Name} -> " +
            $"{state.GetType().Name}");
        CurrentState = state;
    }

    public void Submit() => CurrentState.Submit(this);
    public void Cancel() => CurrentState.Cancel(this);
    public void Ship() => CurrentState.Ship(this);
    public void Deliver() => CurrentState.Deliver(this);
}

Each state class handles only the transitions that make sense:

public sealed class PendingState : IOrderState
{
    public void Submit(OrderContext context)
    {
        Console.WriteLine("Order submitted for processing.");
        context.TransitionTo(new ProcessingState());
    }

    public void Cancel(OrderContext context)
    {
        Console.WriteLine("Order cancelled before submission.");
        context.TransitionTo(new CancelledState());
    }

    public void Ship(OrderContext context)
    {
        throw new InvalidOperationException(
            "Cannot ship a pending order.");
    }

    public void Deliver(OrderContext context)
    {
        throw new InvalidOperationException(
            "Cannot deliver a pending order.");
    }
}

public sealed class ProcessingState : IOrderState
{
    public void Submit(OrderContext context)
    {
        throw new InvalidOperationException(
            "Order is already being processed.");
    }

    public void Cancel(OrderContext context)
    {
        Console.WriteLine(
            "Order cancelled during processing.");
        context.TransitionTo(new CancelledState());
    }

    public void Ship(OrderContext context)
    {
        Console.WriteLine("Order shipped.");
        context.TransitionTo(new ShippedState());
    }

    public void Deliver(OrderContext context)
    {
        throw new InvalidOperationException(
            "Cannot deliver an order still being processed.");
    }
}

Adding a new state like OnHoldState means creating one class. You don't touch PendingState, ProcessingState, or any other existing state. Each state enforces its own transition rules. The OrderContext delegates without knowing the specifics.

Scenario 2: Workflow and Process Management

Business workflows often have states with distinct behaviors and strict transition rules. The state pattern models this naturally. Consider a loan application workflow:

public interface IApplicationState
{
    string StatusName { get; }
    void Review(ApplicationContext context);
    void Approve(ApplicationContext context);
    void Reject(ApplicationContext context);
    void RequestInfo(ApplicationContext context);
}

public sealed class ApplicationContext
{
    public IApplicationState CurrentState { get; private set; }
    public string ApplicantName { get; }
    public List<string> AuditLog { get; } = new();

    public ApplicationContext(string applicantName)
    {
        ApplicantName = applicantName;
        CurrentState = new SubmittedState();
        Log("Application submitted");
    }

    public void TransitionTo(IApplicationState state)
    {
        Log($"Transitioned to {state.StatusName}");
        CurrentState = state;
    }

    public void Log(string message)
    {
        AuditLog.Add(
            $"[{DateTime.UtcNow:u}] {message}");
    }
}

States enforce the business rules:

public sealed class SubmittedState : IApplicationState
{
    public string StatusName => "Submitted";

    public void Review(ApplicationContext context)
    {
        context.Log("Application moved to review.");
        context.TransitionTo(new UnderReviewState());
    }

    public void Approve(ApplicationContext context)
    {
        throw new InvalidOperationException(
            "Cannot approve without review.");
    }

    public void Reject(ApplicationContext context)
    {
        throw new InvalidOperationException(
            "Cannot reject without review.");
    }

    public void RequestInfo(ApplicationContext context)
    {
        context.Log(
            "Additional information requested.");
        context.TransitionTo(
            new AwaitingInfoState());
    }
}

public sealed class UnderReviewState : IApplicationState
{
    public string StatusName => "Under Review";

    public void Review(ApplicationContext context)
    {
        throw new InvalidOperationException(
            "Already under review.");
    }

    public void Approve(ApplicationContext context)
    {
        context.Log("Application approved.");
        context.TransitionTo(new ApprovedState());
    }

    public void Reject(ApplicationContext context)
    {
        context.Log("Application rejected.");
        context.TransitionTo(new RejectedState());
    }

    public void RequestInfo(ApplicationContext context)
    {
        context.Log(
            "More information needed from applicant.");
        context.TransitionTo(
            new AwaitingInfoState());
    }
}

The workflow's rules are explicit and localized. A SubmittedState can't be approved directly -- the business rule is enforced by the state class, not by a distant validation layer. This pattern scales cleanly as workflows grow more complex.

Scenario 3: Game State Management

Games are a natural fit for the state pattern. A character's behavior changes dramatically depending on whether they're idle, moving, attacking, or stunned. Here's a simplified game character:

public interface ICharacterState
{
    void HandleInput(
        CharacterContext character,
        string input);
    void Update(CharacterContext character);
}

public sealed class CharacterContext
{
    public ICharacterState CurrentState { get; private set; }
    public string Name { get; }
    public int Health { get; set; } = 100;

    public CharacterContext(string name)
    {
        Name = name;
        CurrentState = new IdleState();
    }

    public void TransitionTo(ICharacterState state)
    {
        Console.WriteLine(
            $"{Name}: {CurrentState.GetType().Name}" +
            $" -> {state.GetType().Name}");
        CurrentState = state;
    }

    public void HandleInput(string input) =>
        CurrentState.HandleInput(this, input);

    public void Update() =>
        CurrentState.Update(this);
}

public sealed class IdleState : ICharacterState
{
    public void HandleInput(
        CharacterContext character,
        string input)
    {
        switch (input)
        {
            case "move":
                character.TransitionTo(new MovingState());
                break;
            case "attack":
                character.TransitionTo(
                    new AttackingState());
                break;
            default:
                Console.WriteLine(
                    $"{character.Name} is standing still.");
                break;
        }
    }

    public void Update(CharacterContext character)
    {
        // idle animation, passive regen, etc.
    }
}

public sealed class AttackingState : ICharacterState
{
    private int _framesRemaining = 30;

    public void HandleInput(
        CharacterContext character,
        string input)
    {
        // can't interrupt an attack
        Console.WriteLine(
            $"{character.Name} is mid-attack!");
    }

    public void Update(CharacterContext character)
    {
        _framesRemaining--;
        if (_framesRemaining <= 0)
        {
            Console.WriteLine(
                $"{character.Name} finished attacking.");
            character.TransitionTo(new IdleState());
        }
    }
}

Each state handles input differently. The AttackingState ignores movement commands because you can't interrupt an attack. The IdleState responds to both movement and attack inputs. Adding a new state like StunnedState or DodgingState is a self-contained addition -- no existing states need modification.

Scenario 4: UI Component States

UI components often have multiple states that affect rendering and interaction. The state pattern keeps that logic organized. Consider a button component:

public interface IButtonState
{
    string CssClass { get; }
    bool IsClickable { get; }
    void OnClick(ButtonContext button);
    void OnHover(ButtonContext button);
}

public sealed class ButtonContext
{
    public IButtonState CurrentState { get; private set; }
    public string Label { get; }
    public Action? ClickAction { get; set; }

    public ButtonContext(string label, Action clickAction)
    {
        Label = label;
        ClickAction = clickAction;
        CurrentState = new EnabledState();
    }

    public void TransitionTo(IButtonState state)
    {
        CurrentState = state;
        Console.WriteLine(
            $"Button '{Label}' is now " +
            $"{state.GetType().Name} " +
            $"(CSS: {state.CssClass})");
    }

    public void Click() => CurrentState.OnClick(this);
    public void Hover() => CurrentState.OnHover(this);
    public void Enable() =>
        TransitionTo(new EnabledState());
    public void Disable() =>
        TransitionTo(new DisabledState());
}

public sealed class EnabledState : IButtonState
{
    public string CssClass => "btn-enabled";
    public bool IsClickable => true;

    public void OnClick(ButtonContext button)
    {
        Console.WriteLine(
            $"Executing action for '{button.Label}'");
        button.TransitionTo(new LoadingState());
        button.ClickAction?.Invoke();
    }

    public void OnHover(ButtonContext button)
    {
        Console.WriteLine("Showing hover highlight");
    }
}

public sealed class DisabledState : IButtonState
{
    public string CssClass => "btn-disabled";
    public bool IsClickable => false;

    public void OnClick(ButtonContext button)
    {
        Console.WriteLine("Button is disabled.");
    }

    public void OnHover(ButtonContext button)
    {
        Console.WriteLine("Showing disabled tooltip");
    }
}

public sealed class LoadingState : IButtonState
{
    public string CssClass => "btn-loading";
    public bool IsClickable => false;

    public void OnClick(ButtonContext button)
    {
        Console.WriteLine("Operation in progress...");
    }

    public void OnHover(ButtonContext button)
    {
        Console.WriteLine("Loading, please wait...");
    }
}

Each state knows its CSS class, whether it's clickable, and how to respond to user interactions. The LoadingState prevents double-clicks. The DisabledState shows tooltips instead of executing actions. Adding a SuccessState or ErrorState after an async operation completes is straightforward.

Scenario 5: Document Lifecycle Management

Documents typically flow through a lifecycle with strict rules about who can do what at each stage. The state pattern in C# maps directly to this domain:

public interface IDocumentState
{
    string Phase { get; }
    void Edit(DocumentContext doc, string content);
    void SubmitForReview(DocumentContext doc);
    void Publish(DocumentContext doc);
    void Archive(DocumentContext doc);
}

public sealed class DocumentContext
{
    public IDocumentState CurrentState { get; private set; }
    public string Title { get; }
    public string Content { get; set; } = string.Empty;

    public DocumentContext(string title)
    {
        Title = title;
        CurrentState = new DraftDocState();
    }

    public void TransitionTo(IDocumentState state)
    {
        Console.WriteLine(
            $"'{Title}': {CurrentState.Phase}" +
            $" -> {state.Phase}");
        CurrentState = state;
    }

    public void Edit(string content) =>
        CurrentState.Edit(this, content);
    public void SubmitForReview() =>
        CurrentState.SubmitForReview(this);
    public void Publish() =>
        CurrentState.Publish(this);
    public void Archive() =>
        CurrentState.Archive(this);
}

public sealed class DraftDocState : IDocumentState
{
    public string Phase => "Draft";

    public void Edit(DocumentContext doc, string content)
    {
        doc.Content = content;
        Console.WriteLine("Draft updated.");
    }

    public void SubmitForReview(DocumentContext doc)
    {
        if (string.IsNullOrWhiteSpace(doc.Content))
        {
            throw new InvalidOperationException(
                "Cannot submit an empty document.");
        }

        Console.WriteLine("Submitted for review.");
        doc.TransitionTo(new ReviewDocState());
    }

    public void Publish(DocumentContext doc)
    {
        throw new InvalidOperationException(
            "Must go through review before publishing.");
    }

    public void Archive(DocumentContext doc)
    {
        Console.WriteLine("Draft discarded.");
        doc.TransitionTo(new ArchivedDocState());
    }
}

public sealed class ReviewDocState : IDocumentState
{
    public string Phase => "Under Review";

    public void Edit(DocumentContext doc, string content)
    {
        throw new InvalidOperationException(
            "Cannot edit during review.");
    }

    public void SubmitForReview(DocumentContext doc)
    {
        throw new InvalidOperationException(
            "Already under review.");
    }

    public void Publish(DocumentContext doc)
    {
        Console.WriteLine("Document published!");
        doc.TransitionTo(new PublishedDocState());
    }

    public void Archive(DocumentContext doc)
    {
        Console.WriteLine("Review cancelled, archived.");
        doc.TransitionTo(new ArchivedDocState());
    }
}

public sealed class PublishedDocState : IDocumentState
{
    public string Phase => "Published";

    public void Edit(DocumentContext doc, string content)
    {
        throw new InvalidOperationException(
            "Cannot edit a published document directly.");
    }

    public void SubmitForReview(DocumentContext doc)
    {
        throw new InvalidOperationException(
            "Already published.");
    }

    public void Publish(DocumentContext doc)
    {
        throw new InvalidOperationException(
            "Already published.");
    }

    public void Archive(DocumentContext doc)
    {
        Console.WriteLine("Document archived.");
        doc.TransitionTo(new ArchivedDocState());
    }
}

public sealed class ArchivedDocState : IDocumentState
{
    public string Phase => "Archived";

    public void Edit(DocumentContext doc, string content)
    {
        throw new InvalidOperationException(
            "Archived documents are read-only.");
    }

    public void SubmitForReview(DocumentContext doc)
    {
        throw new InvalidOperationException(
            "Cannot review an archived document.");
    }

    public void Publish(DocumentContext doc)
    {
        throw new InvalidOperationException(
            "Cannot publish an archived document.");
    }

    public void Archive(DocumentContext doc)
    {
        Console.WriteLine("Already archived.");
    }
}

The document lifecycle rules are explicit. A draft can be edited. A document under review cannot. A published document can only be archived. Every invalid operation throws with a clear message. Adding a RevisionState that loops back to DraftDocState after publishing is a single new class. This approach pairs well with inversion of control principles -- the context depends on the state abstraction, not on concrete state implementations.

State Pattern vs Alternatives: When to Choose What

Understanding when to use the state pattern in C# means knowing how it stacks up against similar approaches. Here's a comparison:

Criteria State Pattern Strategy Pattern Enum + Switch Boolean Flags
Primary purpose Change behavior based on internal state Swap algorithms at runtime Branch on a status value Toggle between two states
Number of states Many, with distinct behaviors N/A -- swaps algorithms Any, but grows unwieldy Two only
Transition rules Enforced by state classes Not applicable Enforced externally Not applicable
Open/closed principle New state = new class New strategy = new class New state = modify switch Not extensible
Complexity One class per state One class per algorithm Minimal Minimal

The state pattern and the strategy pattern are the most commonly confused pair. A strategy replaces how something is done -- you choose a sorting algorithm, a compression method, or a pricing calculation. The state pattern changes what the object does based on its condition. Strategies are selected externally. States transition internally. If the object itself decides when to switch behavior based on its own lifecycle, that's the state pattern.

The command pattern and the state pattern also overlap in some scenarios. Commands encapsulate operations. States encapsulate behaviors that depend on context. When you need to undo a state transition, you might combine both -- a command that captures the previous state and restores it on undo.

Red Flags: When the State Pattern Is Overkill

Even when the state pattern seems applicable, watch for these signs that the complexity isn't justified.

Your state classes are nearly identical. If every state class implements the same methods with the same logic and only one or two methods differ, the pattern isn't earning its weight. You might be better served by a single class with a status enum and one or two conditional checks.

Transitions are purely linear. If states only ever move forward in a straight line -- draft to review to published -- without branching, looping, or conditional paths, a simple status enum with a CanTransitionTo() method is more readable. The state pattern shines when transitions form a graph, not a line.

You have two or three states with trivial behavior. The minimum viable state pattern involves an interface and at least two or three concrete classes. If those classes each contain five lines of code, the abstraction costs more to navigate than the conditional logic it replaces.

The state changes are driven entirely by external systems. If a workflow engine, message broker, or orchestrator controls all transitions and the object itself never decides to transition, the state pattern's self-managing transition logic goes unused. Let the external system manage state in that case.

Frequently Asked Questions

What is the state pattern in C# and when should I use it?

The state pattern is a behavioral design pattern that lets an object change its behavior when its internal state changes. Use it when an object has multiple states with distinct behaviors and you want to avoid scattering switch or if-else blocks across every method that varies by state. It's especially valuable when transition rules are complex, the number of states is growing, or different developers need to work on different states independently.

How does the state pattern differ from the strategy pattern in C#?

The strategy pattern swaps algorithms at runtime -- the client selects which behavior to use. The state pattern changes behavior based on the object's own internal condition, and transitions happen from within. Strategies are chosen externally. States transition internally. If an object's behavior shifts because of something that happened to it rather than because a caller explicitly selected a different algorithm, you're looking at the state pattern.

Can I use the state pattern with dependency injection in C#?

Yes. You can register state classes in your DI container and resolve them when transitions occur, especially when state classes have their own dependencies. A factory approach works well here -- inject an IStateFactory into the context that creates state instances with their required services already wired up. This keeps the state pattern testable and loosely coupled.

When should I use an enum instead of the state pattern?

Use an enum when your states are primarily data labels -- you store them, display them, compare them -- but they don't drive fundamentally different behavior. If every method in your class does the same thing regardless of the state, or if the behavioral differences are minor enough for a simple switch, an enum is simpler and more familiar. The state pattern is for behavioral variation, not categorical labeling.

How does the state pattern handle invalid state transitions?

Each concrete state class controls which transitions are valid by implementing or rejecting operations. When an invalid action is attempted -- like trying to ship a pending order -- the state class throws an InvalidOperationException with a descriptive message. This is self-documenting. You don't need to look up a transition matrix. Each state class explicitly declares what it can and can't do.

Can the state pattern work with the observer pattern?

Yes. The state pattern handles internal behavior changes while the observer pattern handles external notifications. When a state transition occurs, the context can raise an event that observers subscribe to. For example, when a document transitions from review to published, the context notifies subscribers who might trigger email notifications, update a search index, or log the transition for auditing.

Is the state pattern the same as a finite state machine?

They're closely related but not identical. A finite state machine (FSM) is a mathematical model -- a set of states, transitions, inputs, and outputs. The state pattern is a design pattern that implements FSM-like behavior using object-oriented techniques. You can build a finite state machine without using the state pattern -- a transition table with enums works fine for simple cases. The state pattern is one way to implement an FSM when the behavioral differences between states are significant enough to justify separate classes.

Wrapping Up the State Pattern Decision Guide

Deciding when to use the state pattern in C# comes down to whether your object's behavior genuinely changes based on its internal condition and whether those changes are complex enough to justify separate classes. If you have multiple states with distinct behaviors, non-trivial transition rules, and a state count that's likely to grow, the pattern gives you a clean, extensible architecture where each state is self-contained and self-enforcing.

The decision framework is practical. Check whether behavior varies by state. Ask if you're tired of editing the same switch statement. Confirm that your transition rules are complex enough to benefit from per-state enforcement. And watch for the red flags -- nearly identical state classes, purely linear transitions, trivial behavior differences, and externally driven state changes.

Start with enums and simple conditionals. They're familiar, readable, and sufficient for many situations. When you notice that your conditional branches are multiplying, that new states are getting harder to add, and that the same status check appears in method after method -- that's when the state pattern earns its place. Let the complexity of your actual problem drive the complexity of your solution, not the other way around.

When to Use Command Pattern in C#: Decision Guide with Examples

Discover when to use command pattern in C# with real decision criteria, use case examples, and guidance on when simpler alternatives work better.

State Design Pattern in C#: Complete Guide with Examples

Master the state design pattern in C# with practical examples showing state transitions, behavior changes, and finite state machine implementations.

When to Use Composite Pattern in C#: Decision Guide with Examples

Discover when to use composite pattern in C# with real decision criteria, use case examples, and guidance on when simpler alternatives work better.

An error has occurred. This application may no longer respond until reloaded. Reload