.NET
Programming
Nested Classes
Software Development
C#

Why/when should you use nested classes in .net? Or shouldn't you?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Nested classes in .NET are a design tool, not a default style choice. They work well when a helper type exists only to support one parent type and should stay hidden from broader code. They become harmful when used for arbitrary grouping, because that hurts reuse and makes APIs harder to discover.

What a Nested Type Communicates

A nested class says, in code, that this type belongs to the implementation details or bounded API of another type. That can be valuable documentation.

csharp
1public sealed class CsvParser
2{
3    private sealed class Cursor
4    {
5        public int Index { get; set; }
6    }
7
8    public string[] Parse(string line)
9    {
10        var cursor = new Cursor();
11        var cells = new List<string>();
12
13        while (cursor.Index < line.Length)
14        {
15            int next = line.IndexOf(',', cursor.Index);
16            if (next < 0) next = line.Length;
17            cells.Add(line.Substring(cursor.Index, next - cursor.Index));
18            cursor.Index = next + 1;
19        }
20
21        return cells.ToArray();
22    }
23}

Cursor has no domain meaning outside CsvParser, so nesting is a good fit.

Good Reasons To Nest

Use nesting when these are true:

  • The helper type is tightly coupled to one outer type.
  • Exposing it publicly would confuse consumers.
  • You want to reduce surface area and keep invariants local.

Common examples include parser states, small strategy objects, state machine nodes, or internal comparison helpers.

You can also use nested types for a limited public API scope. For example, event argument types that only make sense with one source type can be nested as public to keep the namespace clean.

csharp
1public class JobRunner
2{
3    public sealed class JobCompletedEventArgs : EventArgs
4    {
5        public string JobId { get; }
6        public TimeSpan Duration { get; }
7
8        public JobCompletedEventArgs(string jobId, TimeSpan duration)
9        {
10            JobId = jobId;
11            Duration = duration;
12        }
13    }
14
15    public event EventHandler<JobCompletedEventArgs>? JobCompleted;
16}

When You Should Not Nest

Do not nest if the type has independent meaning or likely reuse across features.

Bad signal:

  • You want to inject the nested type into multiple services.
  • You need to mock it independently in tests.
  • Multiple parent classes now want the same nested helper.

At that point, promote it to a top-level internal or public type.

csharp
1// Better as top-level if shared by multiple components.
2public sealed class RetryPolicy
3{
4    public int MaxAttempts { get; init; } = 3;
5    public TimeSpan Delay { get; init; } = TimeSpan.FromMilliseconds(200);
6}

Nesting shared policy types creates accidental coupling and awkward references like ServiceA.RetryPolicy used by ServiceB.

Accessibility and Practical Effects

Nested types can be private, internal, protected, protected internal, private protected, or public. The accessibility choice should match intent.

Guidelines:

  • Default to private for implementation details.
  • Use internal if only same assembly code needs it.
  • Use public only when the nested type is clearly part of external API.

Nesting does not create special runtime speed benefits by itself. It is primarily about encapsulation and API clarity.

Testing and Refactoring Signals

Private nested types are not directly unit-tested in most projects, and that is acceptable when behavior is covered through the parent class. If your team repeatedly needs direct tests for a nested helper, that is a signal the helper now deserves its own top-level abstraction.

A practical review checklist:

  • Does the nested type appear in public signatures often.
  • Does another feature want to use it.
  • Are constructor dependencies growing beyond the parent context.
  • Is discoverability in IntelliSense now poor.

If yes, flatten the type.

Common Pitfalls

  • Nesting for visual grouping only. Fix: Use namespaces and folders for organization, and reserve nesting for ownership relationships.
  • Exposing many public nested classes. Fix: Keep API surface small and intuitive; avoid deep qualification in normal usage.
  • Keeping reusable abstractions nested too long. Fix: Promote to top-level types once cross-feature reuse appears.
  • Creating deep nesting levels. Fix: Prefer shallow structures with clear responsibilities.
  • Assuming nesting improves performance. Fix: Treat nesting as an API and maintainability decision, not an optimization.

Summary

  • Nested classes are best when a helper type belongs strictly to one outer type.
  • They improve encapsulation and reduce unnecessary public surface.
  • Avoid nesting for broadly reusable types or independent domain concepts.
  • Choose accessibility levels intentionally, starting from most restrictive.
  • Refactor nested types outward when reuse, testing pressure, or API complexity grows.

Course illustration
Course illustration

All Rights Reserved.