C#のインタフェースのプロパティとプロパティ・アクセサのアクセス制限の詳細

7823 ワード

インタフェースのプロパティは、インタフェースでプロパティを宣言できます.インタフェース・インデックス・アクセサの例を次に示します.

public interface ISampleInterface
{
  // Property declaration:
  string Name
  {
    get;
    set;
  }
}

インタフェースプロパティのアクセサにはボディがありません.したがって、アクセサの目的は、アトリビュートが読み書き、読み取り専用、または書き込み専用であるかどうかを示すことです.この例では、インタフェースIEmployeeには読み書き属性Nameと読み取り専用属性Counterがあります.EmployeeクラスはIEmployeeインタフェースを実装し、この2つのプロパティを使用します.プログラムは、新しい従業員の名前と従業員の現在の番号を読み取り、従業員の名前と計算された従業員番号を表示します.メンバーを宣言するインタフェースを参照するプロパティの完全な限定名を使用できます.例:

string IEmployee.Name
{
  get { return "Employee Name"; }
  set { }
}

これを明示的インタフェース実装(C#プログラミングガイド)と呼ぶ.たとえば、Employeeクラスが2つのインタフェースICitizenとIEmployeeを実装し、両方のインタフェースにName属性がある場合は、明示的なインタフェースメンバー実装が必要です.すなわち、次の属性宣言が行われます.

string IEmployee.Name
{
  get { return "Employee Name"; }
  set { }
}

IEmployeeインタフェースでNameプロパティを実装し、次の宣言を行います.

string ICitizen.Name
{
  get { return "Citizen Name"; }
  set { }
}

ICitizenインタフェースでNameプロパティを実装します.

interface IEmployee
{
  string Name
  {
    get;
    set;
  }

  int Counter
  {
    get;
  }
}

public class Employee : IEmployee
{
  public static int numberOfEmployees;

  private string name;
  public string Name // read-write instance property
  {
    get
    {
      return name;
    }
    set
    {
      name = value;
    }
  }

  private int counter;
  public int Counter // read-only instance property
  {
    get
    {
      return counter;
    }
  }

  public Employee() // constructor
  {
    counter = ++counter + numberOfEmployees;
  }
}

class TestEmployee
{
  static void Main()
  {
    System.Console.Write("Enter number of employees: ");
    Employee.numberOfEmployees = int.Parse(System.Console.ReadLine());

    Employee e1 = new Employee();
    System.Console.Write("Enter the name of the new employee: ");
    e1.Name = System.Console.ReadLine();

    System.Console.WriteLine("The employee information:");
    System.Console.WriteLine("Employee number: {0}", e1.Counter);
    System.Console.WriteLine("Employee name: {0}", e1.Name);
  }
}


たとえば、次のように入力します.

210
Hazem Abolrous


サンプル出力

Enter number of employees: 210
Enter the name of the new employee: Hazem Abolrous
The employee information:
Employee number: 211
Employee name: Hazem Abolrous

アクセサのアクセス性を制限するプロパティまたはインデックスのgetおよびsetセクションを「アクセサ」と呼びます.デフォルトでは、これらのアクセサは同じ可視性またはアクセスレベルを有します.プロパティまたはインデックスの可視性またはアクセスレベルです.ただし、いずれかのアクセサへのアクセスを制限すると便利です.通常、getアクセサの公開アクセスを維持する場合、setアクセサのアクセス性を制限します.例:

private string name = "Hello";

public string Name
{
  get
  {
    return name;
  }
  protected set
  {
    name = value;
  }
}


この例では、Nameというプロパティはgetアクセサとsetアクセサを定義します.getアクセサは、属性自体のアクセス性レベル(この例ではpublic)を受け入れますが、setアクセサでは、アクセサ自体にprotectedアクセス修飾子を適用することで明示的に制限されます.アクセサへのアクセス修飾子の制限プロパティまたはインデックスのアクセス修飾子の使用は、インタフェースまたは明示的なインタフェースメンバーのアクセサ修飾子の使用を実現できないという条件によって制約されます.アクセサ修飾子は、アトリビュートまたはインデックスがsetとgetアクセサを同時に持っている場合にのみ使用できます.この場合、1つのアクセサに対してのみ修飾子を使用できます.プロパティまたはインデックスにoverride修飾子がある場合は、書き換えられたアクセサのアクセサ(ある場合)と一致する必要があります.アクセサのアクセス性レベルは、プロパティまたはインデックス自体のアクセス性レベルよりも厳しく制限されている必要があります.リライト・アクセサのアクセス修飾子は、プロパティまたはインデックスを書き換えるときに、リライトされたアクセサがリライト・コードにアクセス可能である必要があります.さらに、プロパティ/インデックスおよびアクセサのアクセス性レベルは、対応する書き換えられたプロパティ/インデックスおよびアクセサと一致する必要があります.例:

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つのアクセサを使用してインタフェースを実装する場合、次の例に示すように、別のアクセサはアクセス修飾子を有することができる.

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などの制限付きアクセス修飾子を使用する場合、BaseClassのIdプロパティを使用してDerivedClassのIdプロパティを非表示にする方法を示します.したがって、この属性に値を割り当てると、BaseClassクラスの属性が呼び出されます.アクセス修飾子をpublicに置き換えると、このプロパティにアクセスできます.この例では、DelivedClassの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();
  }
}


出力:

  Base: Name-BaseClass, ID-BaseClass
  Derived: John, ID-BaseClass