Rob Lyndon
Rob Lyndon

Reputation: 12661

Nested derived classes have access to private member variables, but not nested or derived classes. Why?

This is inspired by some work I did with a client who liked writing unit tests according to the scheme:

One test class per class under test; one nested class per public method.

So the test classes would look something like this:

public class TestWidget
{
    private Mock<IDoSomething> _mockSomethingDoer = new Mock<IDoSomething>();
    private Widget _widget = new Widget(_mockSomethingDoer);

    public class OpenCan : TestWidget
    {
        [Fact]
        public void GeneratesFroth()
        {
            // ARRANGE
            _mockSomethingDoer.SetUp(...);

            // ACT
            _widget.OpenCan();

            // ASSERT
            _widget.Should().Have().Generated().Froth();
        }

        [Fact]
        public void DoesNotSpillEverywhere()
        {
            // ARRANGE
            _mockSomethingDoer.SetUp(...);

            // ACT
            _widget.OpenCan();

            // ASSERT
            _widget.Should().Not.Have().Spilled().Everywhere();
        }
    }
}

It's a nice scheme, but something about it confuses me. Why does the OpenCan class have access to the private members of TestWidget? It's not because it is a nested class. Take away the derivation from TestWidget and the code will no longer compile. It can't be because it is a derived class: the very definition of private scope forbids access by derived classes. However, if OpenCan is both nested and derived, it somehow magically gains access to the private member variables of TestWidget.

Is this a deliberate feature of the language, or an unexpected side effect?

Upvotes: 0

Views: 170

Answers (1)

Moho
Moho

Reputation: 16498

A nested or inner class has access to the enclosing class' private members. The reason removing inheritance breaks your code is there is no context for accessing the private members (i.e. you don't have an instance of TestWidget with which to access the instance properties/members). If you made private static members in TestWidget, they would be accessible from OpenCan without inheriting from TestWidget

Example of member accessibility (not necessarily useful or a good idea, but it demonstrates the feature):

public class Outer
{
    private int OuterProperty { get; set; }

    public class Inner
    {
        public void UpdateOuter( Outer outer, int value )
        {
            outer.OuterProperty = value;
        }
    }
}

Upvotes: 3

Related Questions