48

Using Object Oriented Programming we have the power to create a class inside a class (a nested class), but I have never created a nested class in my 4 years of coding experience.
What are nested classes good for?

I know that a class can be marked as private if it is nested and that we can access all private members of that class from the containing class. We could just put the variables as private in the containing class itself.
So why create a nested class?

In which scenarios should nested classes be used or are they more powerful in terms of usage over other techniques?

gnat
  • 21,442
  • 29
  • 112
  • 288
mayur rathi
  • 663
  • 1
  • 5
  • 8
  • 1
    You have some good answers and I sometimes will just have some working class or strut that I only need need inside the class. – paparazzo Mar 28 '16 at 18:07
  • 1
    I have 12 years of C# coding experience and I haven't found a case to apply nested classes yet, my concern arose from [java code](https://stackoverflow.com/a/27475129/2188550). I consider nested classes an ugly and useless practice. –  Jul 04 '20 at 00:40

5 Answers5

30

The main feature of nested classes is that they can access private members of the outer class while having the full power of a class itself. Also they can be private which allows for some pretty powerfull encapsulation in certain circumstances:

Here we lock the setter completely down to the factory since the class is private no consumer can downcast it and access the setter, and we can control completely what is allowed.

public interface IFoo 
{
    int Foo{get;}      
}
public class Factory
{
    private class MyFoo : IFoo
    {
        public int Foo{get;set;}
    }
    public IFoo CreateFoo(int value) => new MyFoo{Foo = value};
}

Other than that it is useful for implementing third-party interfaces in a controlled environment where we can still access private members.

If we for example were to provide an instance of some interface to some other object but we don't want our main class to implement it we could let an inner class implement it.

public class Outer
{
    private int _example;
    private class Inner : ISomeInterface
    {
        Outer _outer;
        public Inner(Outer outer){_outer = outer;}
        public int DoStuff() => _outer._example;
    }
    public void DoStuff(){_someDependency.DoBar(new Inner(this)); }
}
Esben Skov Pedersen
  • 5,098
  • 2
  • 21
  • 24
  • In most cases I'd expect delegates to be a cleaner way of doing what you're showing in the second example – Ben Aaronson Mar 30 '16 at 14:40
  • @BenAaronson how would you implement a random interface using delegates? – Esben Skov Pedersen Mar 30 '16 at 16:34
  • @EsbenSkovPedersen Well for your example, instead of passing an instance of `Outer`, you'd pass a `Func`, which would just be `() => _example` – Ben Aaronson Mar 31 '16 at 10:00
  • @BenAaronson in this extremely simple case you are right but for more complex examples, too many delegates becomes clumsy. – Esben Skov Pedersen Mar 31 '16 at 17:45
  • @EsbenSkovPedersen: Your example has some merit, but IMO should only be used in cases where making `Inner` non-nested and `internal` doesn't work (i.e. when you're not dealing with different assemblies). The readability hit from nesting classes makes it less favorable than using `internal` (where possible). – Flater Nov 19 '19 at 10:39
28

Typically, a nested class N is created inside of a class C whenever C needs to use something internally which should never be (directly) used outside of C, and for whatever reason that something needs to be a new type of object rather than some existing type.

I believe this most often happens implementing a method which returns an object implementing some interface, and we want to keep the concrete type of that object hidden because it won't be useful anywhere else.

Implementing IEnumerable is a good example of this:

class BlobOfBusinessData: IEnumerable<BusinessDatum>
{
    public IEnumerator<BusinessDatum> GetEnumerator()
    {
         return new BusinessDatumEnumerator(...);
    }

    class BusinessDatumEnumerator: IEnumerator<BusinessDatum>
    {
        ...
    }
}

There's simply no reason for anyone outside of BlobOfBusinessData to know or care about the concrete BusinessDatumEnumerator type, so we might as well keep it inside BlobOfBusinessData.

That was not meant to be a "best-practices" example of how to implement IEnumerable properly, just the bare minimum to get the idea across, so I left out things like an explicit IEnumerable.GetEnumerator() method.

Ixrec
  • 27,621
  • 15
  • 80
  • 87
  • 11
    Another example that I use with newer programmers is a `Node` class in a `LinkedList`. Anyone using the `LinkedList` doesn't care how the `Node` is implemented, as long as they can access the contents. The only entity that cares at all is the `LinkedList` class itself. – Mage Xy Mar 29 '16 at 19:13
13

So why create a nested class?

I can think of couple of important reasons:

1. Enable encapsulation

Many times nested classes are implementation details of the class. Users of the main class should not have to care about their existence. You should be able to change them at will without requiring the users of the main class to change their code.

2. Avoid name pollution

You should not add types, variables, functions, etc. in a scope unless they are appropriate in that scope. This is slighly different than encapsulation. It could be useful to expose the interface of a nested type but the proper place for the nested type is still the main class. In C++ land, iterator types are one such example. I am not experienced in C# enough to give you concrete examples in it.

Let's make up a simplistic example to illustrate why moving a nested class to the same scope as the main class is name pollution. Let's say you are implementing a linked list class. Normally, you would use

publid class LinkedList
{
   class Node { ... }
   // Use Node to implement the LinkedList class.
}

If you decide to move Node up to the same scope as LinkedList, you will have

public class LinkedListNode
{
}

public class LinkedList
{
  // Use LinkedListNode to implement the class
}

LinkedListNode is unlikely to be useful without LinkedList class itself. Even if LinkedList provided some functions that returnd a LinkedListNode object that a user of LinkedList could use, it still makes LinkedListNode useful only when LinkedList is used. For that reason, making the "node" class a peer class of LinkedList is polluting the containing scope.

R Sahu
  • 1,966
  • 10
  • 15
0
  1. I use public nested classes for related helper classes.

    public class MyRecord {
        // stuff
        public class Comparer : IComparer<MyRecord> {
        }
        public class EqualsComparer : IEqualsComparer<MyRecord> {
        }
    }
    MyRecord[] array;
    Arrays.sort(array, new MyRecord.Comparer());
    
  2. Use them for related variations.

    // Class that may or may not be mutable.
    public class MyRecord {
        protected string name;
        public virtual String Name { get => name; set => throw new InvalidOperation(); }
    
        public Mutable {
            public override String { get => name; set => name = value; }
        }
    }
    
    MyRecord mutableRecord = new MyRecord.Mutable();
    

The caller can choose which version is suitable for which problem. Sometimes a class cannot be fully constructed in one pass, and requires mutable version. This is always true when handling cyclic data. Mutables can be converted to read-only later.

  1. I use them for internal records

    public class MyClass {
        List<Line> lines = new List<Line>();
    
        public void AddUser( string name, string address ) => lines.Add(new Line { Name = name, Address = address });
    
        class Line { string Name; string Address; }
    }
    
Tag
  • 101
  • 1
0

Nested Class can be used whenever you want to create more than once instance of the class or whenever you want to make that type more available.

Nested Class increases the encapsulations as well as it will lead to more readable and maintainable code.

Ishan Shah
  • 339
  • 1
  • 9