Nested Types

Nested Types #

In C#, you can define types within other types. These are called nested types. This is useful when a type is tightly coupled with its containing type, and you want to avoid cluttering the namespace.

public class Car
{
    public class Engine 
    {
        public int HorsePower { get; set; }
        public EngineType Type { get; set; }
    }
    
    public enum EngineType { Gasoline, Diesel, Electric }
}

By default, nested types have a private access modifier, just like other members of classes and structs. However, you can specify any access modifier. A nested type has access to all members of its containing type, including private ones. In the example, the Builder class calls the private constructor of the Pizza class:

public class Pizza
{
    public int SizeCm { get; }
    public IReadOnlyList<Topping> Toppings { get; }
    
    private Pizza(Builder builder)
    {
        SizeCm = builder.SizeCm;
        Toppings = new List<Topping>(builder.Toppings);
    }
    
    public enum Topping { Pepperoni, Sausage, Mushrooms, Cheese, Onions }
    
    public class Builder
    {
        public int SizeCm { get; }
        public List<Topping> Toppings { get; } = new List<Topping>();
        
        public Builder(int sizeCm) => SizeCm = sizeCm;
        
        public Builder AddTopping(Topping topping)
        {
            Toppings.Add(topping);
            return this;
        }
        
        public Pizza Build() => new Pizza(this);
    }
}

From outside the containing class, creating and referencing a nested type requires using its full, qualified name:

Pizza.Builder largePepperoniBuilder = new Pizza.Builder(40);

largePepperoniBuilder.AddTopping(Pizza.Topping.Pepperoni);
largePepperoniBuilder.AddTopping(Pizza.Topping.Cheese);

Pizza largePepperoni = largePepperoniBuilder.Build();