BlackWaspTM

This web site uses cookies. By using the site you accept the cookie policy.This message is for compliance with the UK ICO law.

C# Programming
.NET 1.1+

C# Nested Classes

When one class is entirely dependent upon another, you may decide to implement it using a nested class. Nested classes are declared within the scope of an existing class and receive special benefits when they access their parent class's members.

Increasing Nested Class Visibility

As our ordering system evolves, we may decide that it would be useful to permit other classes access to the nested OrderLine class. We could then modify the AddOrderLine method to accept an OrderLine object rather than its constituent parts. We can do this by changing the access modifier of the nested class to internal, protected internal or public, depending upon the requirements. The following code shows a new version of the code:

class Order
{
    private List<OrderLine> _orderLines = new List<OrderLine>();

    public void AddOrderLine(OrderLine line)
    {
        _orderLines.Add(line);
    }

    public double OrderTotal()
    {
        double total = 0;
        foreach (OrderLine line in _orderLines)
        {
            total += line.OrderLineTotal();
        }
        return total;
    }

    // Nested class
    internal class OrderLine
    {
        public string ProductName { get; set; }
        public int Quantity { get; set; }
        public double Price { get; set; }

        public double OrderLineTotal()
        {
            return Price * Quantity;
        }
    }
}

With the new versions of the classes, the code that creates an order will also be different. Rather than passing the product details as separate variables, the calling class will instantiate order lines and pass these to the AddOrderLine method. When instantiating a nested class, the name of the class must be qualified by prefixing it with the parent class's name, as in the following, updated example. Note that the order lines are created as Order.OrderLine objects.

Order order = new Order();

Order.OrderLine line1 = new Order.OrderLine();
line1.ProductName = "Cheese";
line1.Quantity = 5;
line1.Price = 1.99;
order.AddOrderLine(line1);

Order.OrderLine line2 = new Order.OrderLine();
line2.ProductName = "Oranges";
line2.Quantity = 12;
line2.Price = 0.35;
order.AddOrderLine(line2);

Console.WriteLine(order.OrderTotal());

Accessing Private Members of the Parent Class

The final example will demonstrate the ability for nested classes to access private members of their parent classes. In this example, we have modified the order to include a discount multiplier. The multiplier is held as a private variable that may have been initialised using a constructor or a property. In this case the value is fixed at 0.85. Every order line value will be multiplied by this amount to give a 15% discount.

To allow the order lines to access the discount multiplier, the OrderLineTotal method has been updated to include a parameter. This parameter accepts an Order object. The method retrieves the private discount multiplier from the Order and includes it in the calculation, rounding the result to two decimal places on a line-by-line basis. If the OrderLine class was not nested within Order, this would not be possible.

class Order
{
    private List<OrderLine> _orderLines = new List<OrderLine>();
    private double DiscountMultiplier = 0.85;

    public void AddOrderLine(OrderLine line)
    {
        _orderLines.Add(line);
    }

    public double OrderTotal()
    {
        double total = 0;
        foreach (OrderLine line in _orderLines)
        {
            total += line.OrderLineTotal(this);
        }
        return total;
    }

    // Nested class
    internal class OrderLine
    {
        public string ProductName { get; set; }
        public int Quantity { get; set; }
        public double Price { get; set; }

        public double OrderLineTotal(Order order)
        {
            return Math.Round(Price * Quantity * order.DiscountMultiplier, 2);
        }
    }
}

NB: Although nested classes can access the private members of their parent class, the reverse is not true. Private members of nested classes are invisible to their parent class.

21 March 2009