アクセサーのアクセシビリティの制限 (C# プログラミング ガイド)

プロパティやインデクサーの 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 アクセス修飾子をアクセサー自体に適用することにより、明示的に制限されています。

アクセス修飾子によるアクセサーの制限

プロパティやインデクサーでアクセス修飾子を使用する際には、以下の条件が適用されます。

  • アクセス修飾子は、インターフェイスや明示的なインターフェイス メンバー実装で使用できません。

  • アクセス修飾子を使用できるのは、プロパティやインデクサーが setget の両方のアクセサーを備えている場合に限られます。 この場合、修飾子は、これら 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 { }
    }
}

アクセサーのアクセシビリティ ドメイン

アクセサーでアクセス修飾子を使用した場合は、この修飾子によって、アクセサーのアクセシビリティ ドメインが決定されます。

アクセサーでアクセス修飾子を使用しない場合は、プロパティやインデクサーのアクセシビリティ レベルによって、アクセサーのアクセシビリティ ドメインが決定されます。

使用例

次の例には、BaseClassDerivedClassMainClass の 3 つのクラスがあります。 BaseClass には NameId の 2 つのプロパティがあり、これらのプロパティは派生クラスにもあります。 この例は、protectedprivate などの制限付きのアクセス修飾子を使用したときに、DerivedClassId プロパティを BaseClassId プロパティによってどのように隠ぺいできるかを示しています。 そのため、前者のプロパティに値を割り当てると、代わりに BaseClass クラスのプロパティが呼び出されます。 アクセス修飾子を public に置き換えると、このプロパティにアクセスできるようになります。

また、次の例は、privateprotected などの制限付きのアクセス修飾子を、DerivedClassName プロパティの 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 Idnew public string Id に置き換えると、次の出力が得られます。

Name and ID in the base class: Name-BaseClass, ID-BaseClass

Name and ID in the derived class: John, John123

参照

C# プログラミング ガイド
プロパティ
インデクサー
アクセス修飾子