private protected

private protected (C# Reference)

C#에서 어떤 멤버를 어디까지 공개할지 정하는 '접근 한정자(access modifier)' 가운데 하나예요. private protected 멤버는 그 클래스에서 파생된 타입이면서, 동시에 그 클래스가 들어 있는 어셈블리 안에서 선언된 타입만 접근할 수 있어요. 다른 접근 한정자들과 한눈에 비교하고 싶다면 Accessibility Levels를 보면 돼요.

출처: private protected (C# Reference)

본문

파생 타입이 기본 클래스의 private protected 멤버에 접근할 수 있는 조건이 하나 더 붙어요. 그 멤버에 접근하는 변수의 정적 타입이 파생 클래스 타입이어야 해요. 즉, 안전하게는 '같은 어셈블리에 있는 파생 클래스'지만, 실제로는 '파생 클래스 인스턴스를 거쳐서'만 접근할 수 있다는 뜻이에요. 코드로 확인해 볼게요:

// Assembly1.cs
// Compile with: /target:library
public class BaseClass
{
    private protected int myValue = 0;
}

public class DerivedClass1 : BaseClass
{
    void Access()
    {
        var baseObject = new BaseClass();

        // Error CS1540, because myValue can only be accessed by
        // classes derived from BaseClass.
        // baseObject.myValue = 5;

        // OK, accessed through the current derived class instance
        myValue = 5;
    }
}
// Assembly2.cs
// Compile with: /reference:Assembly1.dll
class DerivedClass2 : BaseClass
{
    void Access()
    {
        // Error CS0122, because myValue can only be
        // accessed by types in Assembly1
        // myValue = 10;
    }
}

이 예시는 Assembly1.csAssembly2.cs 두 파일로 되어 있어요. 첫 번째 파일에는 public 기본 클래스 BaseClass와 그로부터 파생된 DerivedClass1이 들어 있어요. BaseClassprivate protected 멤버 myValue를 갖고 있는데, DerivedClass1은 같은 어셈블리 안에서 상속받은 멤버로 이 값에 접근할 수 있어요.

두 번째 파일에서는 DerivedClass2가 상속받은 멤버로 myValue에 접근하려고 하면 오류가 나요. 이유는 private protected 멤버는 같은 어셈블리 안의 파생 타입만 접근할 수 있기 때문이에요. 여기가 바로 protected(어느 어셈블리의 파생 클래스든 접근 가능)나 protected internal(같은 어셈블리의 모든 클래스, 또는 어느 어셈블리의 파생 클래스까지 접근 가능)과 가장 크게 갈리는 지점이에요.

만약 Assembly1.csAssembly2를 이름으로 지정한 xref:System.Runtime.CompilerServices.InternalsVisibleToAttribute가 있다면, 파생 클래스 DerivedClass2BaseClass에 선언된 private protected 멤버에 접근할 수 있게 돼요. InternalsVisibleToprivate protected 멤버를 다른 어셈블리의 파생 클래스에 보이게 만들어 주는 거죠.

다른 protected 접근 한정자와의 비교

세 가지 protected 접근 한정자의 차이를 표로 정리하면 이렇게 돼요:

Access Modifier Same Assembly, Derived Class Same Assembly, Non-derived Class Different Assembly, Derived Class
protected ✔️ ✔️
protected internal ✔️ ✔️ ✔️
private protected ✔️
  • protected어느 어셈블리의 파생 클래스에서 멤버에 접근하게 하고 싶을 때 써요.
  • protected internal은 가장 관대한 접근을 허용할 때 써요(같은 어셈블리의 어떤 클래스, 또는 어디서든 파생 클래스).
  • private protected는 가장 제한적인 protected 접근을 원할 때 써요(같은 어셈블리 안의 파생 클래스만).

참고로 private protected는 구조체(struct) 멤버에는 선언할 수 없어요. 구조체는 상속이 불가능하거든요.

C# 언어 사양

자세한 사양은 C# 언어 사양 문서를 참고하면 돼요.

더 알아보기