protected internal

protected internal (C# 참조)

protected internal 키워드 조합은 멤버 접근 한정자(member access modifier)예요. protected internal 멤버는 현재 어셈블리(assembly) 안이거나, 해당 멤버를 포함하는 클래스에서 파생된 타입이라면 어디서든 접근할 수 있어요. protected internal을 다른 접근 한정자와 비교해서 보고 싶다면 Accessibility Levels를 참고하세요.

출처: protected internal - C# reference

본문

포함하는 어셈블리 안의 어떤 타입이든 기반 클래스의 protected internal 멤버에 접근할 수 있어요. 다른 어셈블리에 있는 파생 클래스는, 파생 클래스 타입의 변수를 통해 접근할 때만 그 멤버에 접근할 수 있죠. 예를 들어 다음 코드 조각을 볼게요.

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

class TestAccess
{
    void Access()
    {
        var baseObject = new BaseClass();
        baseObject.myValue = 5;
    }
}
// Assembly2.cs
// Compile with: /reference:Assembly1.dll
class DerivedClass : BaseClass
{
    static void Main()
    {
        var baseObject = new BaseClass();
        var derivedObject = new DerivedClass();

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

        // OK, because this class derives from BaseClass.
        derivedObject.myValue = 10;
    }
}

이 예시는 Assembly1.csAssembly2.cs 두 파일로 이루어져 있어요. 첫 번째 파일에는 public 기반 클래스인 BaseClass와 다른 클래스 TestAccess가 들어 있어요. BaseClassprotected internal 멤버인 myValue를 갖고 있는데, TestAccess 타입은 같은 어셈블리 안에 있기 때문에 이 멤버에 접근하는 거예요. 두 번째 파일에서는 BaseClass 인스턴스를 통해 myValue에 접근하려 하면 오류가 나지만, 파생 클래스인 DerivedClass 인스턴스를 통한 접근은 성공해요. 이 접근 규칙을 보면 protected internal이 같은 어셈블리 안의 어떤 클래스든, 혹은 어떤 어셈블리에 있든 파생 클래스면 접근을 허용한다는 걸 알 수 있어요. 그래서 protected 계열 접근 한정자들 가운데 가장 허용 범위가 넓은 한정자예요.

구조체(struct) 멤버는 protected internal일 수 없어요. 구조체는 상속될 수 없기 때문이에요.

Overriding protected internal members

가상(virtual) 멤버를 재정의(override)할 때, 재정의된 메서드의 접근 한정자 수준은 파생 클래스를 정의하는 어셈블리가 어디냐에 따라 달라져요.

파생 클래스를 기반 클래스와 같은 어셈블리에 정의하면, 재정의된 모든 멤버는 protected internal 접근을 갖게 돼요. 반대로 파생 클래스를 기반 클래스와 다른 어셈블리에 정의하면, 재정의된 멤버는 protected 접근만 갖게 되죠.

// Assembly1.cs
// Compile with: /target:library
public class BaseClass
{
    protected internal virtual int GetExampleValue()
    {
        return 5;
    }
}

public class DerivedClassSameAssembly : BaseClass
{
    // Override to return a different example value, accessibility modifiers remain the same.
    protected internal override int GetExampleValue()
    {
        return 9;
    }
}
// Assembly2.cs
// Compile with: /reference:Assembly1.dll
class DerivedClassDifferentAssembly : BaseClass
{
    // Override to return a different example value, since this override
    // method is defined in another assembly, the accessibility modifiers
    // are only protected, instead of protected internal.
    protected override int GetExampleValue()
    {
        return 2;
    }
}

C# language specification

[!INCLUDECSharplangspec]

더 알아보기