0

Why can't users of subclasses of private classes access public member data of the private class? The following seems very counter-intuitive to me in that it won't compile:

public class OuterClassBase {
    private class PrivateInnerClass {
        public void DoSomething () {}
    }

    protected class ProtectedInnerClass : PrivateInnerClass {}
}


public class OuterClassDerived : OuterClassBase {
    public OuterClassDerived () {
        ProtectedInnerClass o = new ProtectedInnerClass();
        o.DoSomething(); // inaccessible due to its pretection level
    }
}

Making PrivateInnerClass public/protected allows the code to compile...

Thomas Eding
  • 35,312
  • 13
  • 75
  • 106
  • 1
    I assume OuterClassDerived should be OuterClassDerived : OuterClassBase? – James Michael Hare Jul 20 '12 at 20:51
  • That's just basic scope rules in C#. Public scope is accessible outside the class. Private scope is accessible inside the class. Protected scope is available inside the class and in derived classes. – devstruck Jul 20 '12 at 20:53
  • Counter-Intuitive? How so, if you could access a private class outside of the scope it was defined in, now that would be counter intuitive. – Tony Hopkinson Jul 20 '12 at 20:58
  • Making `PrivateInnerClass` `protected` will allow it to compile. – D Stanley Jul 20 '12 at 20:58
  • **Note:** Only inner classes can be declared as [protected](http://stackoverflow.com/questions/1017778/protected-classes-in-net) – DJH Jul 20 '12 at 21:02
  • 1
    The whole of `OuterClassDerived` is a red herring here - your protected subclass doesn't compile on its own! (Just get rid of the second half of the program - the first half still doesn't compile.) – Jon Skeet Jul 20 '12 at 21:16

3 Answers3

4

From section 3.5 of the C# 4 spec:

Declarations of members allow control over member access. The accessibility of a member is established by the declared accessibility (§3.5.1) of the member combined with the accessibility of the immediately containing type, if any.
...
Access to a member is permitted when the textual location in which the access takes place is included in the accessibility domain (§3.5.2) of the member.

Then in section 3.5.2 (accessibility domains):

The accessibility domain of a nested member M declared in a type T within a program P is defined as follows (noting that M itself may possibly be a type):

  • If the declared accessibility of M is public, the accessibility domain of M is the accessibility domain of T.
  • ...
  • If the declared accessibility of M is private, the accessibility domain of M is the program text of T.

This is the case here. So the accessibility domain of DoSomething is the accessibility domain of PrivateInnerClass by the first bullet... but the accessibility domain of PrivateInnerClass is the program text of OuterClassBase by the final bullet.

Therefore the call within OuterClassDerived is not in the accessibility domain of DoSomething, so it can't call it.

I'm actually surprised that you can derive ProtectedInnerClass from PrivateInnerClass in the first place...

EDIT: And it turns out you can't... even having removed the OuterClassDerived class entirely, you get this error:

Test.cs(10,21): error CS0060: Inconsistent accessibility: base class
        'OuterClassBase.PrivateInnerClass' is less accessible than class
        'OuterClassBase.ProtectedInnerClass'

This violates section 10.1.4.1 of the specification:

The direct base class of a class type must be at least as accessible as the class type itself (§3.5.2). For example, it is a compile-time error for a public class to derive from a private or internal class.

Here you're trying to derive a protected class from a private class - the protected class is more accessible than the private class, hence the error.

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

PrivateInnerClass is private to OuterClassBase - no one except OuterClassBase can use it (this is the meaning of private).

Subclassing it doesn't change the rules, it is still private - if the subclassing will break the private constraint and allow someone outside of OuterBaseClass to access members of PrivateInnerClass than this is illegal and won't compile.

In other word if something is declared private than it is private, any trick that would allow you to by pass the private declaration should not compile (except reflections).

Nir
  • 29,306
  • 10
  • 67
  • 103
  • But the subclassing happens inside of the class X that can access PrivateInnerClass. That is, X owns PrivateInnerClass, so why would this be a problem? As such, I don't get why this breaks the private constraint. – Thomas Eding Jul 20 '12 at 21:03
  • @trinithis PrivateInnerClass.DoSomething is private to OuterBaseClass (because PrivateInnerClass is private), any code that let you access PrivateInnerClass.DoSomething from outside OuterBaseClass is illegal because no one, not even OuterBaseClass is allowed to undo the constraints of the PrivateInnerClass deceleration – Nir Jul 20 '12 at 22:02
0

The protected class cannot inherit from the private class for the same reason that public classes cannot inherit from internal classes: A class cannot be more accessible than its base class.

But why are you trying to do this? You can keep other classes from inheriting directly from the PrivateInnerClass, but only if they're in a different assembly. You could also do something like this; the framework does it a lot with internal/public classes:

public class OuterClassBase
{
    private class PrivateInnerClass : ProtectedInnerClass
    {
    }

    protected abstract class ProtectedInnerClass
    {
        public void DoSomething() { }
    }

    protected ProtectedInnerClass ProtectedInnerClassFactoryMethod()
    {
        return new PrivateInnerClass();
    }
}

public class OuterClassDerived : OuterClassBase
{
    public OuterClassDerived()
    {
        ProtectedInnerClass o = ProtectedInnerClassFactoryMethod();
        o.DoSomething();
    }
} 
phoog
  • 42,068
  • 6
  • 79
  • 117