비대칭 접근자 액세스 가능성(C# 프로그래밍 가이드)
업데이트: 2007년 11월
속성이나 인덱서의 get 및 set 부분을 접근자라고 합니다. 기본적으로 이러한 접근자의 표시 여부(액세스 수준)는 이 접근자가 속한 속성이나 인덱서의 경우와 동일합니다. 자세한 내용은 액세스 가능성 수준을 참조하십시오. 그러나 때로는 이러한 접근자 중 하나에 대한 액세스를 제한해야 할 수도 있습니다. 일반적인 예로는 set 접근자의 액세스 가능성을 제한한 채 get 접근자를 계속 공용으로 액세스할 수 있도록 유지하는 경우를 들 수 있습니다. 예를 들면 다음과 같습니다.
private string name = "Hello";
public string Name
{
get
{
return name;
}
protected set
{
name = value;
}
}
이 예제에서 Name이라는 속성은 get 및 set 접근자를 정의합니다. get 접근자는 속성 자체와 동일한 수준(이 경우 public)으로 액세스 가능성이 설정되는 반면, set 접근자는 이 접근자 자체에 protected 액세스 한정자를 적용하여 액세스가 명시적으로 제한됩니다.
접근자에 대한 액세스 한정자의 제한
속성이나 인덱서에 대한 접근자 한정자를 사용하려면 다음과 같은 조건을 준수해야 합니다.
인터페이스나 명시적 인터페이스 멤버 구현에는 접근자 한정자를 사용할 수 없습니다.
접근자 한정자는 속성이나 인덱서에 set 및 get 접근자가 모두 있는 경우에만 사용할 수 있습니다. 이 경우 한정자는 두 접근자 중 하나에 대해서만 허용됩니다.
속성이나 인덱서에 재정의 한정자가 있는 경우 재정의된 접근자의 접근자가 있으면 접근자 한정자가 이와 일치해야 합니다.
접근자에 대한 액세스 수준은 속성이나 인덱서 자체에 대한 액세스 수준보다 더 제한적이어야 합니다.
재정의 접근자에 대한 액세스 한정자
속성이나 인덱서를 재정의하는 경우 재정의 코드에서는 재정의된 접근자에 액세스할 수 있어야 합니다. 또한 속성과 인덱서 모두의 액세스 수준 및 접근자의 액세스 수준은 상응하는 재정의된 속성과 인덱서 및 접근자의 액세스 수준과 일치해야 합니다. 예를 들면 다음과 같습니다.
public class Parent
{
public virtual int TestProperty
{
// Notice the accessor accessibility level.
protected set { }
// No access modifier is used here.
get { return 0; }
}
}
public class Kid : Parent
{
public override int TestProperty
{
// Use the same accessibility level as in the overridden accessor.
protected set { }
// Cannot use access modifier here.
get { return 0; }
}
}
인터페이스 구현
접근자를 사용하여 인터페이스를 구현하는 경우 접근자에는 액세스 한정자가 없을 수 있습니다. 그러나 get 같은 접근자 하나를 사용하여 인터페이스를 구현하는 경우에는 다음 예제에서와 같이 다른 접근자에 액세스 한정자가 있을 수 있습니다.
public interface ISomeInterface
{
int TestProperty
{
// No access modifier allowed here
// because this is an interface.
get;
}
}
public class TestClass : ISomeInterface
{
public int TestProperty
{
// Cannot use access modifier here because
// this is an interface implementation.
get { return 10; }
// Interface property does not have set accessor,
// so access modifier is allowed.
protected set { }
}
}
접근자 액세스 가능 도메인
접근자에 대해 액세스 한정자를 사용하는 경우 접근자의 액세스 가능 도메인은 이 한정자를 통해 결정됩니다.
접근자에 대해 액세스 한정자를 사용하지 않는 경우 접근자의 액세스 가능 도메인은 속성이나 인덱서의 액세스 수준에 따라 결정됩니다.
예제
다음 예제에는 BaseClass, DerivedClass 및 MainClass라는 세 가지 클래스가 들어 있습니다. BaseClass에 대한 속성 두 개가 있고 나머지 두 클래스에 모두 Name 및 Id가 있습니다. 이 예제에서는 protected 또는 private 같은 제한된 액세스 한정자를 사용할 때 DerivedClass의 Id 속성을 BaseClass의 Id 속성으로 숨기는 방법을 보여 줍니다. 따라서 이 속성에 값을 할당하면 BaseClass 클래스의 속성이 대신 호출됩니다. 액세스 한정자를 public으로 바꾸면 속성에 액세스할 수 있습니다.
이 예제에서는 DerivedClass에서 Name 속성의 set 접근자에 대한 private 또는 protected 같은 제한적 액세스 한정자로 접근자에 대한 액세스를 막고 여기에 할당하는 경우 오류를 생성하는 방법도 보여 줍니다.
public class BaseClass
{
private string name = "Name-BaseClass";
private string id = "ID-BaseClass";
public string Name
{
get { return name; }
set { }
}
public string Id
{
get { return id; }
set { }
}
}
public class DerivedClass : BaseClass
{
private string name = "Name-DerivedClass";
private string id = "ID-DerivedClass";
new public string Name
{
get
{
return name;
}
// Using "protected" would make the set accessor not accessible.
set
{
name = value;
}
}
// Using private on the following property hides it in the Main Class.
// Any assignment to the property will use Id in BaseClass.
new private string Id
{
get
{
return id;
}
set
{
id = value;
}
}
}
class MainClass
{
static void Main()
{
BaseClass b1 = new BaseClass();
DerivedClass d1 = new DerivedClass();
b1.Name = "Mary";
d1.Name = "John";
b1.Id = "Mary123";
d1.Id = "John123"; // The BaseClass.Id property is called.
System.Console.WriteLine("Base: {0}, {1}", b1.Name, b1.Id);
System.Console.WriteLine("Derived: {0}, {1}", d1.Name, d1.Id);
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Output:
Base: Name-BaseClass, ID-BaseClass
Derived: John, ID-BaseClass
*/
주석
new private string Id 선언을 new public string Id로 바꾸는 경우 출력은 다음과 같습니다.
Name and ID in the base class: Name-BaseClass, ID-BaseClass
Name and ID in the derived class: John, John123