|
|
連載:[完全版]究極のC#プログラミング
Chapter9 プロパティとアクセシビリティ
川俣 晶
2009/11/30 |
|
9.1 プロパティアクセサのアクセシビリティ
C# 3.0では、プロパティのsetアクセサとgetアクセサに対して、異なるアクセシビリティを制限できる。これにより、getアクセサはpublicだが、setアクセサはprotectedという非対称のプロパティを宣言できる。
書き方は簡単で、getまたはsetキーワードの手前に、アクセシビリティを指定するキーワードを追加するだけである。それによって、プロパティ宣言そのものに付いているアクセシビリティ指定を上書きする(リスト9.1参照)。
using System;
class A
{
private string s;
public string SampleProp // 本来public指定だが……
{
get { return s; } // 本来のpublic指定が有効
protected set { s = value; } // protectedで上書きしている
}
}
class B : A
{
public void Initialize()
{
SampleProp = "by class B";
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
b.Initialize();
Console.WriteLine(b.SampleProp); // 出力:by class B
}
}
|
|
リスト9.1 getはpublicだがsetはprotectedの例 |
さて、この機能は継承が絡むとややこしい問題を併発する場合がある。その事例を紹介しよう。
次のリスト9.2は、継承関係のある2つのクラスの双方が同じ名前のプロパティを宣言している例である。このコードでは、クラスBのSamplePropプロパティはprotectedなので、外部からはアクセスできない。だから、Mainメソッドが利用しているのはクラスAのSamplePropである。このように、アクセスできないプロパティをスキップし、アクセスできるプロパティが使われるようになっている。
using System;
class A
{
private string s;
public string SampleProp
{
get { return s; }
set { s = value; }
}
}
class B : A
{
private string s;
protected new string SampleProp // protectedなプロパティ
{
get { return s; }
set { s = value; }
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
b.SampleProp = "Sample";
Console.WriteLine(b.SampleProp); // 出力:Sample
}
}
|
|
リスト9.2 正常に動作するケース |
ここで、クラスBのプロパティをpublicにし、getアクセサとsetアクセサで異なるアクセシビリティを持たせてみよう。リスト9.2のクラスBをリスト9.3の内容に差し替えてみる。
class B : A
{
private string s;
public new string SampleProp
{
protected get { return s; }
set { s = value; }
}
}
|
|
リスト9.3 リスト9.2のクラスBを差し替える |
すると、次のようなエラーが起きてコンパイルできない。
get アクセサにアクセスできないため、プロパティまたはインデクサ'B.SampleProp' はこのコンテキストでは使用できません。
|
|
最初の例から考えると、protectedなSamplePropのgetアクセサを飛ばして、クラスAのSamplePropのgetアクセサを使ってくれそうに思えるかもしれないが、そのようには動作していない。get/setの手前のアクセシビリティ指定は、メンバーの検索やオーバーロードの解決には影響しないからである。つまり、getアクセサのprotectedに関係なく、クラスBのpublicなSamplePropプロパティは発見されてしまい、それにprotectedが付いているためにアクセスできないというエラーになるわけである。
Insider.NET 記事ランキング
本日
月間