非対称アクセサのアクセシビリティ (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 の両方のアクセサを備えている場合に限られます。この場合、修飾子は、これら 2 つのアクセスのうちの一方でのみ許可されます。
プロパティやインデクサにオーバーライド修飾子がある場合、アクセス修飾子は、オーバーライドされたアクセサのアクセサに一致する必要があります。
アクセサのアクセシビリティ レベルは、プロパティやインデクサ自体のアクセシビリティ レベルよりも制限する必要があります。
アクセサのオーバーライド時のアクセス修飾子
プロパティやインデクサをオーバーライドした場合、オーバーライドされたアクセサは、オーバーライド側のコードにアクセスできる必要があります。また、プロパティとインデクサの両方のアクセシビリティ レベル、およびアクセサのアクセシビリティ レベルは、オーバーライドされた、対応するプロパティとインデクサ、およびアクセサに適合する必要があります。次に例を示します。
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 などの 1 つのアクセサを使用してインターフェイスを実装する場合は、次の例に示すように、もう 1 つのアクセサでアクセス修飾子を使用できます。
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 の 3 つのクラスがあります。BaseClass には Name と Id の 2 つのプロパティがあり、これらのプロパティは派生クラスにもあります。この例は、protected や private などの制限付きのアクセス修飾子を使用したときに、DerivedClass の Id プロパティを BaseClass の Id プロパティによってどのように隠ぺいできるかを示しています。そのため、前者のプロパティに値を割り当てると、代わりに BaseClass クラスのプロパティが呼び出されます。アクセス修飾子を public に置き換えると、このプロパティにアクセスできるようになります。
また、次の例は、private や protected などの制限付きのアクセス修飾子を、DerivedClass の Name プロパティの set アクセサに指定すると、このアクセサにアクセスできなくなり、このプロパティに値を割り当てると、エラーが生成されることも示しています。
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