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

.NetClassNestedFxcop

.Net Problem Overview


In Kathleen Dollard's 2008 blog post, she presents an interesting reason to use nested classes in .net. However, she also mentions that FxCop doesn't like nested classes. I'm assuming that the people writing FxCop rules aren't stupid, so there must be reasoning behind that position, but I haven't been able to find it.

.Net Solutions


Solution 1 - .Net

Use a nested class when the class you are nesting is only useful to the enclosing class. For instance, nested classes allow you to write something like (simplified):

public class SortedMap {
    private class TreeNode {
        TreeNode left;
        TreeNode right;
    }
}

You can make a complete definition of your class in one place, you don't have to jump through any PIMPL hoops to define how your class works, and the outside world doesn't need to see anything of your implementation.

If the TreeNode class was external, you would either have to make all the fields public or make a bunch of get/set methods to use it. The outside world would have another class polluting their intellisense.

Solution 2 - .Net

From Sun's Java Tutorial:

Why Use Nested Classes? There are several compelling reasons for using nested classes, among them:

  • It is a way of logically grouping classes that are only used in one place.
  • It increases encapsulation.
  • Nested classes can lead to more readable and maintainable code.

Logical grouping of classes—If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together. Nesting such "helper classes" makes their package more streamlined.

Increased encapsulation—Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared private. By hiding class B within class A, A's members can be declared private and B can access them. In addition, B itself can be hidden from the outside world. <- This doesn't apply to C#'s implementation of nested classes, this only applies to Java.

More readable, maintainable code—Nesting small classes within top-level classes places the code closer to where it is used.

Solution 3 - .Net

Fully Lazy and thread-safe singleton pattern

public sealed class Singleton
{
    Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            return Nested.instance;
        }
    }
    
    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton();
    }
}

source: https://csharpindepth.com/Articles/Singleton

Solution 4 - .Net

It depends on the usage. I rarely would ever use a Public nested class but use Private nested classes all of the time. A private nested class can be used for a sub-object that is intended to be used only inside the parent. An example of this would be if a HashTable class contains a private Entry object to store data internally only.

If the class is meant to be used by the caller (externally), I generally like making it a separate standalone class.

Solution 5 - .Net

In addition to the other reasons listed above, there is one more reason that I can think of not only to use nested classes, but in fact public nested classes. For those who work with multiple generic classes that share the same generic type parameters, the ability to declare a generic namespace would be extremely useful. Unfortunately, .Net (or at least C#) does not support the idea of generic namespaces. So in order to accomplish the same goal, we can use generic classes to fulfill the same goal. Take the following example classes related to a logical entity:

public  class       BaseDataObject
                    <
                        tDataObject, 
                        tDataObjectList, 
                        tBusiness, 
                        tDataAccess
                    >
        where       tDataObject     : BaseDataObject<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataObjectList : BaseDataObjectList<tDataObject, tDataObjectList, tBusiness, tDataAccess>, new()
        where       tBusiness       : IBaseBusiness<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataAccess     : IBaseDataAccess<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
}

public  class       BaseDataObjectList
                    <
                        tDataObject, 
                        tDataObjectList, 
                        tBusiness, 
                        tDataAccess
                    >
:   
                    CollectionBase<tDataObject>
        where       tDataObject     : BaseDataObject<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataObjectList : BaseDataObjectList<tDataObject, tDataObjectList, tBusiness, tDataAccess>, new()
        where       tBusiness       : IBaseBusiness<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataAccess     : IBaseDataAccess<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
}

public  interface   IBaseBusiness
                    <
                        tDataObject, 
                        tDataObjectList, 
                        tBusiness, 
                        tDataAccess
                    >
        where       tDataObject     : BaseDataObject<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataObjectList : BaseDataObjectList<tDataObject, tDataObjectList, tBusiness, tDataAccess>, new()
        where       tBusiness       : IBaseBusiness<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataAccess     : IBaseDataAccess<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
}

public  interface   IBaseDataAccess
                    <
                        tDataObject, 
                        tDataObjectList, 
                        tBusiness, 
                        tDataAccess
                    >
        where       tDataObject     : BaseDataObject<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataObjectList : BaseDataObjectList<tDataObject, tDataObjectList, tBusiness, tDataAccess>, new()
        where       tBusiness       : IBaseBusiness<tDataObject, tDataObjectList, tBusiness, tDataAccess>
        where       tDataAccess     : IBaseDataAccess<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{
}

We can simplify the signatures of these classes by using a generic namespace (implemented via nested classes):

public
partial class   Entity
                <
                    tDataObject, 
                    tDataObjectList, 
                    tBusiness, 
                    tDataAccess
                >
        where   tDataObject     : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.BaseDataObject
        where   tDataObjectList : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.BaseDataObjectList, new()
        where   tBusiness       : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.IBaseBusiness
        where   tDataAccess     : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.IBaseDataAccess
{

    public  class       BaseDataObject {}

    public  class       BaseDataObjectList : CollectionBase<tDataObject> {}
    
    public  interface   IBaseBusiness {}
    
    public  interface   IBaseDataAccess {}

}

Then, through the use of partial classes as suggested by Erik van Brakel in an earlier comment, you can separate the classes into separate nested files. I recommend using a Visual Studio extension like NestIn to support nesting the partial class files. This allows the "namespace" class files to also be used to organize the nested class files in a folder like way.

For example:

Entity.cs

public
partial class   Entity
                <
                    tDataObject, 
                    tDataObjectList, 
                    tBusiness, 
                    tDataAccess
                >
        where   tDataObject     : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.BaseDataObject
        where   tDataObjectList : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.BaseDataObjectList, new()
        where   tBusiness       : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.IBaseBusiness
        where   tDataAccess     : Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>.IBaseDataAccess
{
}

Entity.BaseDataObject.cs

partial class   Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{

    public  class   BaseDataObject
    {

        public  DataTimeOffset  CreatedDateTime     { get; set; }
        public  Guid            CreatedById         { get; set; }
        public  Guid            Id                  { get; set; }
        public  DataTimeOffset  LastUpdateDateTime  { get; set; }
        public  Guid            LastUpdatedById     { get; set; }

        public
        static
        implicit    operator    tDataObjectList(DataObject dataObject)
        {
            var returnList  = new tDataObjectList();
            returnList.Add((tDataObject) this);
            return returnList;
        }

    }
    
}

Entity.BaseDataObjectList.cs

partial class   Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{

    public  class   BaseDataObjectList : CollectionBase<tDataObject>
    {

        public  tDataObjectList ShallowClone() 
        {
            var returnList  = new tDataObjectList();
            returnList.AddRange(this);
            return returnList;
        }
    
    }

}

Entity.IBaseBusiness.cs

partial class   Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{

    public  interface   IBaseBusiness
    {
        tDataObjectList Load();
        void            Delete();
        void            Save(tDataObjectList data);
    }

}

Entity.IBaseDataAccess.cs

partial class   Entity<tDataObject, tDataObjectList, tBusiness, tDataAccess>
{

    public  interface   IBaseDataAccess
    {
        tDataObjectList Load();
        void            Delete();
        void            Save(tDataObjectList data);
    }

}

The files in the visual studio solution explorer would then be organized as such:

Entity.cs
+   Entity.BaseDataObject.cs
+   Entity.BaseDataObjectList.cs
+   Entity.IBaseBusiness.cs
+   Entity.IBaseDataAccess.cs

And you would implement the generic namespace like the following:

User.cs

public
partial class   User
:
                Entity
                <
                    User.DataObject, 
                    User.DataObjectList, 
                    User.IBusiness, 
                    User.IDataAccess
                >
{
}

User.DataObject.cs

partial class   User
{

    public  class   DataObject : BaseDataObject 
    {
        public  string  UserName            { get; set; }
        public  byte[]  PasswordHash        { get; set; }
        public  bool    AccountIsEnabled    { get; set; }
    }
    
}

User.DataObjectList.cs

partial class   User
{

    public  class   DataObjectList : BaseDataObjectList {}

}

User.IBusiness.cs

partial class   User
{

    public  interface   IBusiness : IBaseBusiness {}

}

User.IDataAccess.cs

partial class   User
{

    public  interface   IDataAccess : IBaseDataAccess {}

}

And the files would be organized in the solution explorer as follows:

User.cs
+   User.DataObject.cs
+   User.DataObjectList.cs
+   User.IBusiness.cs
+   User.IDataAccess.cs

The above is a simple example of using an outer class as a generic namespace. I've built "generic namespaces" containing 9 or more type parameters in the past. Having to keep those type parameters synchronized across the nine types that all needed to know the type parameters was tedious, especially when adding a new parameter. The use of generic namespaces makes that code far more manageable and readable.

Solution 6 - .Net

If I understand Katheleen's article right, she proposes to use nested class to be able to write SomeEntity.Collection instead of EntityCollection< SomeEntity>. In my opinion it's controversial way to save you some typing. I'm pretty sure that in real world application collections will have some difference in implementations, so you will need to create separate class anyway. I think that using class name to limit other class scope is not a good idea. It pollutes intellisense and strengthen dependencies between classes. Using namespaces is a standard way to control classes scope. However I find that usage of nested classes like in @hazzen comment is acceptable unless you have tons of nested classes which is a sign of bad design.

Solution 7 - .Net

I often use nested classes to hide implementation detail. An example from Eric Lippert's answer here:

abstract public class BankAccount
{
    private BankAccount() { }
    // Now no one else can extend BankAccount because a derived class
    // must be able to call a constructor, but all the constructors are
    // private!
    private sealed class ChequingAccount : BankAccount { ... }
    public static BankAccount MakeChequingAccount() { return new ChequingAccount(); }
    private sealed class SavingsAccount : BankAccount { ... }
}

This pattern becomes even better with use of generics. See this question for two cool examples. So I end up writing

Equality<Person>.CreateComparer(p => p.Id);

instead of

new EqualityComparer<Person, int>(p => p.Id);

Also I can have a generic list of Equality<Person> but not EqualityComparer<Person, int>

var l = new List<Equality<Person>> 
        { 
         Equality<Person>.CreateComparer(p => p.Id),
         Equality<Person>.CreateComparer(p => p.Name) 
        }

where as

var l = new List<EqualityComparer<Person, ??>>> 
        { 
         new EqualityComparer<Person, int>>(p => p.Id),
         new EqualityComparer<Person, string>>(p => p.Name) 
        }

is not possible. That's the benefit of nested class inheriting from parent class.

Another case (of the same nature - hiding implementation) is when you want to make a class's members (fields, properties etc) accessible only for a single class:

public class Outer 
{
   class Inner //private class
   {
       public int Field; //public field
   }

   static inner = new Inner { Field = -1 }; // Field is accessible here, but in no other class
}

Solution 8 - .Net

Another use not yet mentioned for nested classes is the segregation of generic types. For example, suppose one wants to have some generic families of static classes that can take methods with various numbers of parameters, along with values for some of those parameters, and generate delegates with fewer parameters. For example, one wishes to have a static method which can take an Action<string, int, double> and yield a String<string, int> which will call the supplied action passing 3.5 as the double; one may also wish to have a static method which can take an an Action<string, int, double> and yield an Action<string>, passing 7 as the int and 5.3 as the double. Using generic nested classes, one can arrange to have the method invocations be something like:

MakeDelegate<string,int>.WithParams<double>(theDelegate, 3.5);
MakeDelegate<string>.WithParams<int,double>(theDelegate, 7, 5.3);

or, because the latter types in each expression can be inferred even though the former ones can't:

MakeDelegate<string,int>.WithParams(theDelegate, 3.5);
MakeDelegate<string>.WithParams(theDelegate, 7, 5.3);

Using the nested generic types makes it possible to tell which delegates are applicable to which parts of the overall type description.

Solution 9 - .Net

The nested classes can be used for following needs:

  1. Classification of the data
  2. When the logic of the main class is complicated and you feel like you require subordinate objects to manage the class
  3. When you that the state and existence of the class fully depends on the enclosing class

Solution 10 - .Net

As nawfal mentioned implementation of Abstract Factory pattern, that code can be axtended to achieve Class Clusters pattern which is based on Abstract Factory pattern.

Solution 11 - .Net

I like to nest exceptions that are unique to a single class, ie. ones that are never thrown from any other place.

For example:

public class MyClass
{
    void DoStuff()
    {
        if (!someArbitraryCondition)
        {
            // This is the only class from which OhNoException is thrown
            throw new OhNoException(
                "Oh no! Some arbitrary condition was not satisfied!");
        }
        // Do other stuff
    }

    public class OhNoException : Exception
    {
        // Constructors calling base()
    }
}

This helps keep your project files tidy and not full of a hundred stubby little exception classes.

Solution 12 - .Net

Bear in mind that you'll need to test the nested class. If it is private, you won't be able to test it in isolation.

You could make it internal, though, in conjunction with the InternalsVisibleTo attribute. However, this would be the same as making a private field internal only for testing purposes, which I consider bad self-documentation.

So, you may want to only implement private nested classes involving low complexity.

Solution 13 - .Net

yes for this case:

class Join_Operator
{

    class Departamento
    {
        public int idDepto { get; set; }
        public string nombreDepto { get; set; }
    }

    class Empleado
    {
        public int idDepto { get; set; }
        public string nombreEmpleado { get; set; }
    }

    public void JoinTables()
    {
        List<Departamento> departamentos = new List<Departamento>();
        departamentos.Add(new Departamento { idDepto = 1, nombreDepto = "Arquitectura" });
        departamentos.Add(new Departamento { idDepto = 2, nombreDepto = "Programación" });

        List<Empleado> empleados = new List<Empleado>();
        empleados.Add(new Empleado { idDepto = 1, nombreEmpleado = "John Doe." });
        empleados.Add(new Empleado { idDepto = 2, nombreEmpleado = "Jim Bell" });

        var joinList = (from e in empleados
                        join d in departamentos on
                        e.idDepto equals d.idDepto
                        select new
                        {
                            nombreEmpleado = e.nombreEmpleado,
                            nombreDepto = d.nombreDepto
                        });
        foreach (var dato in joinList)
        {
            Console.WriteLine("{0} es empleado del departamento de {1}", dato.nombreEmpleado, dato.nombreDepto);
        }
    }
}

Solution 14 - .Net

Base on my understanding of this concept we could use this feature when classes are related to each other conceptually. I mean some of them are complete one Item in our business like entities that exist in the DDD world that help to an aggregate root object to complete its business logic.

In order to clarify I'm going to show this via an example:

Imagine that we have two classes like Order and OrderItem. In order class, we are going to manage all orderItems and in OrderItem we are holding data about a single order for clarification, you can see below classes:

 class Order
    {
        private List<OrderItem> _orderItems = new List<OrderItem>();

        public void AddOrderItem(OrderItem line)
        {
            _orderItems.Add(line);
        }

        public double OrderTotal()
        {
            double total = 0;
            foreach (OrderItem item in _orderItems)
            {
                total += item.TotalPrice();
            }

            return total;
        }

        // Nested class
        public class OrderItem
        {
            public int ProductId { get; set; }
            public int Quantity { get; set; }
            public double Price { get; set; }
            public double TotalPrice() => Price * Quantity;
        }
    }

    class Program
    {

        static void Main(string[] args)
        {
            Order order = new Order();

            Order.OrderItem orderItem1 = new Order.OrderItem();
            orderItem1.ProductId = 1;
            orderItem1.Quantity = 5;
            orderItem1.Price = 1.99;
            order.AddOrderItem(orderItem1);

            Order.OrderItem orderItem2 = new Order.OrderItem();
            orderItem2.ProductId = 2;
            orderItem2.Quantity = 12;
            orderItem2.Price = 0.35;
            order.AddOrderItem(orderItem2);

            Console.WriteLine(order.OrderTotal());
            ReadLine();
        }


    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEric HaskinsView Question on Stackoverflow
Solution 1 - .NethazzenView Answer on Stackoverflow
Solution 2 - .NetEsteban ArayaView Answer on Stackoverflow
Solution 3 - .Netkay.oneView Answer on Stackoverflow
Solution 4 - .NetChris DailView Answer on Stackoverflow
Solution 5 - .NetTyree JacksonView Answer on Stackoverflow
Solution 6 - .NetakuView Answer on Stackoverflow
Solution 7 - .NetnawfalView Answer on Stackoverflow
Solution 8 - .NetsupercatView Answer on Stackoverflow
Solution 9 - .NetRachin GoyalView Answer on Stackoverflow
Solution 10 - .NetdiimdeepView Answer on Stackoverflow
Solution 11 - .NetEric DandView Answer on Stackoverflow
Solution 12 - .Nettm1View Answer on Stackoverflow
Solution 13 - .NetAlex MartinezView Answer on Stackoverflow
Solution 14 - .NetHamidView Answer on Stackoverflow