접근 수준 사용 제한
접근 수준 사용 제한 (C# 참조)
선언에서 어떤 타입을 지정할 때, 그 타입의 접근 수준이 다른 멤버나 타입의 접근 수준에 의존하는지 한번 짚어볼 필요가 있어요. 예를 들어 직접 베이스 클래스는 파생 클래스만큼은 접근이 가능해야 합니다. 아래 선언은 컴파일 오류를 일으키는데, 베이스 클래스 BaseClass가 MyClass보다 접근 수준이 낮기 때문이에요.
class BaseClass {...}
public class MyClass: BaseClass {...} // Error
이렇게 생긴 규칙은 낯설게 느껴질 수 있는데요, 실제로는 단순합니다. 바로 "어떤 대상이 그 타입을 쓰는 코드보다 덜 접근 가능해서는 안 된다"는 원칙이에요. 덜 접근 가능한 타입을 더 접근 가능한 곳에서 사용하면, 그 타입을 사용하는 쪽에서 접근이 막혀 버리니까 컴파일러가 애초에 막아 버리는 거죠. 아래 목록에 선언된 접근 수준 제한을 정리해 두었어요.
- 클래스: 클래스 타입의 직접 베이스 클래스는 그 클래스 타입 자체만큼은 접근 가능해야 합니다.
- 인터페이스: 인터페이스 타입의 명시적 베이스 인터페이스는 그 인터페이스 타입 자체만큼은 접근 가능해야 합니다.
- 대리자: 대리자 타입의 반환 타입과 매개변수 타입은 그 대리자 타입 자체만큼은 접근 가능해야 합니다.
- 상수: 상수의 타입은 그 상수 자체만큼은 접근 가능해야 합니다.
- 필드: 필드의 타입은 그 필드 자체만큼은 접근 가능해야 합니다.
- 메서드: 메서드의 반환 타입과 매개변수 타입은 그 메서드 자체만큼은 접근 가능해야 합니다.
- 속성: 속성의 타입은 그 속성 자체만큼은 접근 가능해야 합니다.
- 이벤트: 이벤트의 타입은 그 이벤트 자체만큼은 접근 가능해야 합니다.
- 인덱서: 인덱서의 타입과 매개변수 타입은 그 인덱서 자체만큼은 접근 가능해야 합니다.
- 연산자: 연산자의 반환 타입과 매개변수 타입은 그 연산자 자체만큼은 접근 가능해야 합니다.
- 생성자: 생성자의 매개변수 타입은 그 생성자 자체만큼은 접근 가능해야 합니다.
아래 예시에는 여러 타입의 잘못된 선언이 들어 있어요. 각 선언 뒤의 주석이 기대되는 컴파일 오류를 알려 줍니다.
// Restrictions on Using Accessibility Levels
// CS0052 expected as well as CS0053, CS0056, and CS0057
// To make the program work, change access level of both class B
// and MyPrivateMethod() to public.
using System;
// A delegate:
delegate int MyDelegate();
class B
{
// A private method:
static int MyPrivateMethod()
{
return 0;
}
}
public class A
{
// Error: The type B is less accessible than the field A.myField.
public B myField = new B();
// Error: The type B is less accessible
// than the constant A.myConst.
public readonly B myConst = new B();
public B MyMethod()
{
// Error: The type B is less accessible
// than the method A.MyMethod.
return new B();
}
// Error: The type B is less accessible than the property A.MyProp
public B MyProp
{
set
{
}
}
MyDelegate d = new MyDelegate(B.MyPrivateMethod);
// Even when B is declared public, you still get the error:
// "The parameter B.MyPrivateMethod is not accessible due to
// protection level."
public static B operator +(A m1, B m2)
{
// Error: The type B is less accessible
// than the operator A.operator +(A,B)
return new B();
}
static void Main()
{
Console.Write("Compiled successfully");
}
}
본문
타입 B가 class B로 선언되어 public이 아니라는 점을 눈여겨보세요. 그런데 클래스 A의 필드, 상수, 메서드 반환 타입, 속성, 연산자 등에서 이 B를 사용하니 컴파일러가 하나같이 오류를 냅니다. B가 public보다 낮은 접근 수준이라, public인 A의 멤버 선언에서 타입으로 쓰일 수 없기 때문이에요. 주석에 나온 것처럼 class B와 MyPrivateMethod()를 모두 public으로 바꾸면 프로그램이 컴파일됩니다.
여기서 한 가지 더 짚을 점이 있어요. MyDelegate d = new MyDelegate(B.MyPrivateMethod); 줄을 보면, B를 public으로 고쳐도 여전히 오류가 남습니다. 이번에는 "매개변수 B.MyPrivateMethod가 보호 수준 때문에 접근할 수 없다"는 오류인데요, MyPrivateMethod()가 static이면서 private이기 때문이에요. 즉 타입 자체의 접근 수준을 고치더라도, 그 내부 멤버의 접근 수준까지 챙겨야 한다는 걸 보여 주는 좋은 예입니다.
정리하면 이렇게요. 어떤 타입을 선언에 쓰려면, 그 타입이 선언이 위치한 접근 수준보다 내부에 감춰져 있어서는 안 됩니다. 베이스 클래스, 반환 타입, 매개변수 타입, 필드·속성·이벤트 타입 할 것 없이 모두 같은 원칙이에요. 그리고 반드시 기억할 점은, 타입뿐 아니라 멤버의 접근 수준까지 함께 점검해야 한다는 거예요. 접근 수준 제한은 컴파일 타임에 잡아 주므로, 코드가 실행되기 전에 문제를 발견할 수 있어서 안전합니다.