Udostępnij za pośrednictwem


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.

Comments

  • Anonymous
    October 05, 2017
    As a good blogging tip, can you please add the links to all the previous blogs in the series or atleast to the previous post?
    • Anonymous
      October 09, 2017
      Thanks for the good tip! I will update all posts in the series to include a TOC then.
  • Anonymous
    October 05, 2017
    How comes you do not mention 'private' any where where you are talking about levels of accessibility?
    • Anonymous
      October 09, 2017
      Thanks for the catch! I added private now.
  • Anonymous
    October 06, 2017
    I think it should be internal protected and not private protected
    • Anonymous
      October 09, 2017
      The CLR already had a Protected And Internal scope, and C#'s language has taken the protected internal for other accessibility (see my beginning list.)
    • Anonymous
      November 17, 2017
      The issue is that initially when designing the language .NET (I assume for the sake of simplicity) had the concepts of external visibility (published) and internal visibility conflated together as a single class visibility definition. In retrospect it might have been better to offer an "export" term/attribute for published and "internal" as the default to separate responsibilities and to combine with "public" or "protected" for class visibility. Technically although they are related they are different concepts, except for the "private" modifier which is never exported outside the class.So, if "internal protected" didn't already mean having "export protected" visibility and "internal public" visibility then that would make more sense. The current implementation of "internal protected" visibility is truly a strange beast, but I can see some rare use cases for it. However, none of those use cases wouldn't be served by supplying two separate methods with one being exported and the other not.
  • Anonymous
    October 09, 2017
    Sensational, thank you so much for sharing!
  • Anonymous
    November 20, 2017
    Cool features, might be useful in the future. But the naming starts to get confusing now... I guess too late to change now, eh? :\
  • Anonymous
    December 12, 2017
    Great approach to C # 7, many new features, lots of cool stuff!