プロパティ (プログラミング)

出典: フリー百科事典『ウィキペディア(Wikipedia)』

これはこのページの過去の版です。Aegialina (会話 | 投稿記録) による 2020年12月16日 (水) 06:46個人設定で未設定ならUTC)時点の版 (追記)であり、現在の版とは大きく異なる場合があります。

プロパティ: property) はオブジェクト指向プログラミング言語において、フィールドアクセスのカプセル化を実現するための言語機能および構文の一種である。

概要

オブジェクト指向プログラミングの重要な概念であるカプセル化を実現するためには、クラスのフィールドへの単純な値の設定/取得に対しても何らかのアクセス制御を行う必要がある。 これに対する専用の言語機能および構文を、いくつかのプログラミング言語においてプロパティと呼ぶ。

プロパティを用いることで、カプセル化を実現しつつも、フィールドに直接アクセスしているかのような直感的な記述が可能となる。

    // C# のプロパティ構文を利用した際のフィールドアクセスの例
    Person person = new Person();
    // set アクセス
    person.Name = "John";
    // get アクセス
    string userName = person.Name;

プロパティを持たない言語では、メソッドを利用したカプセル化を行うことが多い。

    // Java のアクセサメソッドを利用した際のフィールドアクセスの例
    Person person = new Person();
    // set アクセス
    person.setName("John");
    // get アクセス
    String userName = person.getName();

プロパティの読み書きは、構文上はフィールドと同様に行なえるものの、実際にはアクセサ (getter/setter) の呼び出しに変換される。あたかもフィールドであるかのように代入および読み出しを記述できるので、メソッドを呼び出すより簡潔で、かつ操作の意味が明確で直感的な記述が可能となる。一方で、内部ではメソッドの呼び出しとなるので、データの取得・設定に際して介入を加えることが可能になる。また、読み取り専用 (read)、書き込み専用 (write)、あるいは読み書き両用 (read/write) のプロパティを定義することや、個別にアクセス権を設定することもできる。例えば、設定される値を事前に検証・制限したり、内部データと異なる単位に換算した後の数値を返す読み取り専用プロパティを設けてGUI表示に利用したりすることができる。

このようなことから、プロパティはフィールドとメソッドの中間的な存在と考えることができ、また高水準なカプセル化の実現にも使われる。

サポート言語

プロパティ機能を持つ代表的なプログラミング言語として、Object Pascal (Delphi)、PythonObjective-C、そしてC#Visual Basic .NETをはじめとする.NET言語などが挙げられる。COMもプロパティの概念をサポートし、言語や処理系によってはプロパティ構文を利用できる。C++はプロパティをサポートしないが、Microsoft Visual C++などは独自拡張としてプロパティ構文をサポートする。

Javaは言語レベルでプロパティをサポートしないが、類似機能としてBean (JavaBeans) がある。Kotlinなど、Java VM上で動作する後発言語にはプロパティ機能をサポートするものもある。

C#

C#においては、クラスおよび構造体の内部にプロパティを持つことができる。

明示的なバッキングフィールドを持つプロパティ

明示的にバッキングフィールド (backing field) を記述する基本的なプロパティの例を示す。

プロパティの構文内ではget, setが、またsetアクセサ内ではvalueがコンテキスト(文脈)キーワードとして機能する。

  class Person {
      /// バッキングフィールド
      private string name;

      /// nameをカプセル化するプロパティ
      public string Name {
          get { return name; }
          set {
              if (value == null) { throw new ArgumentNullException(); }
              name = value;
          }
      }
  }

呼び出し側では、フィールドにアクセスするような構文でプロパティの機能を呼び出す。

  var person = new Person();
  // set アクセス
  person.Name = "John";
  // get アクセス
  string userName = person.Name;
仮想プロパティ、抽象プロパティ

プロパティをvirtualabstractキーワードで修飾することで、仮想メソッドあるいは抽象メソッドと同様に継承先での扱いを指定することができる。

  abstract class AbstractPerson {
      private string name;

      // 仮想プロパティは継承先でオーバーライド可能となる
      public virtual string Name {
          get { return name; }
          set { name = value; }
      }
      // 抽象プロパティは継承先で実装が必須となる
      public abstract int Age { get; set; }
  }

  interface IPerson {
      // 抽象プロパティは実装先で実装が必須となる
      int Age { get; set; }
  }
片方のアクセサのみの実装

片方のみのアクセサを実装するプロパティを宣言できる。

  class Person {
      private string age;

      public string Age {
          // getのみ実装することで、読み取り専用とする
          get { return age; }
      }
  }
非対称なアクセスレベル指定

片方のアクセサに対して、より厳しいアクセスレベルを指定することができる。

C# 2.0で導入された。

  class Person {
      private string address;

      public string Address {
          // getのアクセスレベルは public
          get { return address; }
          // setのアクセスレベルは protected
          protected set { address = value; }
      }
  }

自動実装プロパティ

値の取得と設定のみを行い、取得設定時に追加の処理を行わない場合、自動実装プロパティ (auto-implemented properties) と呼ばれる簡易な構文を用いることができる。

自動実装プロパティでは、バッキングフィールドが内部的に自動生成される。 プログラマは自動生成されたバッキングフィールドには直接アクセスすることはできない。

C# 3.0で導入された。

  class Person {
      // バッキングフィールドが(不可視ではあるが)自動生成されている
      public string Job { get; set; }
  }

自動実装プロパティと抽象的なプロパティは構文が類似しているため、注意を要する。

  abstract class AbstractPerson {
      // バッキングフィールドは生成されない
      // 継承先のクラスで実装を要求される抽象的なプロパティ
      public abstract string Name { get; set; }
  }

  interface IPerson {
      // バッキングフィールドは生成されない
      // 実装先のクラスで実装を要求される抽象的なプロパティ
      string Name { get; set; }
  }
getアクセサのみの自動実装プロパティ

getアクセサのみを指定することで、読み取り専用の自動実装プロパティを利用することができる。

getアクセサのみの自動実装プロパティのバッキングフィールドは、コンストラクタによってのみ値を初期化できる。

C# 6.0で導入された。

  class Person {
      // getアクセサと対応するバッキングフィールドが生成される
      public int YearOfBirth { get; }

      public Person(int year) {
          // コンストラクタ内でバッキングフィールドを初期化可能
          YearOfBirth = year;
      }
  }
自動実装プロパティの初期化

自動実装プロパティで自動生成されるバッキングフィールドの初期値を指定することができる。

C# 6.0で導入された。

  class Person {
      // バッキングフィールドの初期値を指定、setアクセサで書き換えも可能
      public string Name { get; set; } = "Newborn";
      // バッキングフィールドの初期値を指定、読み取り専用
      public int Age { get; } = 0;
  }

簡略記法

式本体のプロパティ

読み取り専用のプロパティにおいて、式本体の書式を利用できる。

この場合、get文脈キーワードは使用しない。

C# 6.0で導入された。

  class Person {
      private int age;
      // 読み取り専用のプロパティになる
      public int Age => age;
  }
式本体のアクセサ

それぞれのアクセサに対して、式本体の書式を利用できる。

C# 7.0で導入された。

  class Person {
        private string name;
        // get set それぞれで式本体の書式を利用する
        public string Name {
            get => name ?? "NO NAME";
            set => name = value ?? throw new ArgumentNullException();
        }
  }

スニペット

Microsoft Visual Studio IDE や Visual Studio Code では、C#のプロパティを素早く記述しやすくするための以下のようなコードスニペットが用意されている。

  • propfull : バッキングフィールドを有するプロパティ
  • prop : 自動実装プロパティ
  • propg : 読み取り専用な自動実装プロパティ

参考文献


関連項目