proposals/csharp-7.2/private-protected.md
Champion issue: https://github.com/dotnet/csharplang/issues/37
Expose the CLR protectedAndInternal accessibility level in C# as private protected.
There are many circumstances in which an API contains members that are only intended to be implemented and used by subclasses contained in the assembly that provides the type. While the CLR provides an accessibility level for that purpose, it is not available in C#. Consequently API owners are forced to either use internal protection and self-discipline or a custom analyzer, or to use protected with additional documentation explaining that, while the member appears in the public documentation for the type, it is not intended to be part of the public API. For examples of the latter, see members of Roslyn's CSharpCompilationOptions whose names start with Common.
Directly providing support for this access level in C# enables these circumstances to be expressed naturally in the language.
private protected access modifierWe propose to add a new access modifier combination private protected (which can appear in any order among the modifiers). This maps to the CLR notion of protectedAndInternal, and borrows the same syntax currently used in C++/CLI.
A member declared private protected can be accessed within a subclass of its container if that subclass is in the same assembly as the member.
We modify the language specification as follows (additions in bold). Section numbers are not shown below as they may vary depending on which version of the specification it is integrated into.
The declared accessibility of a member can be one of the following:
Depending on the context in which a member declaration takes place, only certain types of declared accessibility are permitted. Furthermore, when a member declaration does not include any access modifiers, the context in which the declaration takes place determines the default declared accessibility.
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 might possibly be a type):
When a protected or private protected instance member is accessed outside the program text of the class in which it is declared, and when a protected internal instance member is accessed outside the program text of the program in which it is declared, the access shall take place within a class declaration that derives from the class in which it is declared. Furthermore, the access is required to take place through an instance of that derived class type or a class type constructed from it. This restriction prevents one derived class from accessing protected members of other derived classes, even when the members are inherited from the same base class.
The permitted access modifiers and the default access for a type declaration depend on the context in which the declaration takes place (§9.5.2):
A static class declaration is subject to the following restrictions:
It is a compile-time error to violate any of these restrictions.
A class-member-declaration can have any one of the
fivesix possible kinds of declared accessibility (§9.5.2): public, private protected, protected internal, protected, internal, or private. Except for the protected internal and private protected combinations, it is a compile-time error to specify more than one access modifier. When a class-member-declaration does not include any access modifiers, private is assumed.
Non-nested types can have public or internal declared accessibility and have internal declared accessibility by default. Nested types can have these forms of declared accessibility too, plus one or more additional forms of declared accessibility, depending on whether the containing type is a class or struct:
The method overridden by an override declaration is known as the overridden base method For an override method M declared in a class C, the overridden base method is determined by examining each base class type of C, starting with the direct base class type of C and continuing with each successive direct base class type, until in a given base class type at least one accessible method is located which has the same signature as M after substitution of type arguments. For the purposes of locating the overridden base method, a method is considered accessible if it is public, if it is protected, if it is protected internal, or if it is either internal or private protected and declared in the same program as C.
The use of accessor-modifiers is governed by the following restrictions:
Since inheritance isn’t supported for structs, the declared accessibility of a struct member cannot be protected, private protected, or protected internal.
As with any language feature, we must question whether the additional complexity to the language is repaid in the additional clarity offered to the body of C# programs that would benefit from the feature.
An alternative would be the provision of an API combining an attribute and an analyzer. The attribute is placed by the programmer on an internal member to indicates that the member is intended to be used only in subclasses, and the analyzer checks that those restrictions are obeyed.
The implementation is largely complete. The only open work item is drafting a corresponding specification for VB.
TBD