C# 7 Series, Part 5: Private Protected

C# has several accessibility modifiers, public, internal, internal protected, and private.

  • Public: The member declared with this accessibility can be visible within the assembly containing this member, or any other assembly that references the containing assembly. i.e., access is not limited.
  • Internal: The member declared with this accessibility can be visible within the assembly containing this member, it is not visible to any assembly outside of the containing assembly. i.e., access is limited to containing assembly only.
  • Protected: The member declared with this accessibility can be visible within the types derived from the containing type within the containing assembly, and the types derived from the containing type outside of the containing assembly. i.e., access is limited to derived types of the containing type.
  • Internal Protected: The member declared with this accessibility can be visible within the types derived from the containing type within or outside of the containing assembly, it is also visible to any types within the containing assembly. i.e., access is limited to containing assembly or derived types.
  • Private: The member declared with this accessibility can be visible within the containing type, it is not visible to any derived types, other types in the same assembly or types outside of the containing assembly. i.e., access is limited to the containing type only.

Private Protected

C# 7.2 is adding a new level of accessibility: private protected. This is to match the same access level that has already been in the CLR.

  • Private Protected: The member declared with this accessibility can be visible within the types derived from this containing type within the containing assembly. It is not visible to any types not derived from the containing type, or outside of the containing assembly. i.e., the access is limited to derived types within the containing assembly.

This is very helpful if developers want to implement something only visible to internal assembly level.

Example

To demonstrate the behavior of private protected, I created one solution that contains two projects: one is a Library project, another is a Console App project referencing the Library project. I created types within the Library project:

 public class Base
{
     protected private void M()
     {
         Console.WriteLine("From Base.M()");
     }
}
 
public class D1 : Base
{
     new public void M()
     {
         Console.WriteLine("From D1.M()");
         base.M();
     }
}

In the Base class, I declared a private protected member M(), then in the D1 class that is derived from Base, I created a method M() and call base.M() internally. These two types are within the same assembly, so I should have access to base.M() from D1.

I then created another class C:

 public class C
{
    public void M()
    {
        Base b = new Base();
        b.M();

        D1 d = new D1();
        d.M();
    }
}

I was trying to call b.M() in C.M() method, because C is not derived from Base, I don’t have the access to Base.M(), hence the code will not work; I saw this compilation error.

image

Lastly, I created a type in the Console App project that is not the containing assembly for Base. If I tried to access Base.M() there, I would be given this compilation error:

image

NOTE: To make this work, you will need to upgrade your project to C# 7.2 or latest,

image

Conclusion

Now with C# 7.2, we have five levels of accessibility: public, internal, protected, internal protected, and private protected. The addition of private protected will benefit from limiting the access to only derived types within the containing assembly to have special internal implementation for some members. Read more on this Private Protected page for more details.