[C#] 21. C#のプロパティ(Property)


Study / C#    作成日付 : 2019/07/13 00:56:20   修正日付 : 2021/09/02 17:36:37

こんにちは。明月です。


この投稿はC#のプロパティ(Property)に関する説明です。


以前の投稿でオブジェクト指向プログラミング(OOP)の4つの原則とアクセス修飾子、カプセル化に関して説明したことがあります。

link - [C#] 12. Staticとアクセス修飾子、そしてカプセル化

link - [C#] 20. オブジェクト指向プログラミング(OOP)の4つの原則(カプセル化、抽象化、継承化、多相化(ポリモーフィズム))


基本的にオブジェクト指向プログラミングでメンバー変数はprivateに設定してクラスの外部から接続ができないように設定します。そうならクラスのメンバー変数の値はすべてコンストラクタや関数を通ってデータを設定しますが、そのところでデータを格納、取得だけの関数があります。

それをJava言語ではゲッター(getter)、セッター(setter)と言います。

using System;
 
namespace Example
{
  // クラス
  class Program
  {
    // メンバー変数
    private int data;
    // メンバー変数の値を設定するセッター(setter)
    public void SetData(int data)
    {
      this.data = data;
    }
    // メンバー変数の値を取得するゲッター(getter)
    public int GetData()
    {
      return this.data;
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // インスタンス生成
      Program p = new Program();
      // Programのインスタンスのメンバー変数のdataを設定
      p.SetData(10);
      // Programのメンバー変数を取得してコンソールに出力
      Console.WriteLine("p - data = " + p.GetData());
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


何でこのように実装するかというとメンバー変数はオブジェクト指向プログラミングによりメンバー変数はprivateに設定することが原則です。

上の例は何の制限がなしてゲッター、セッターを設定したからデータ設定、取得することにしますが、ゲッター、セッターで権限により、あるいは設定によりデータのアクセスを制御することが可能です。

例えば、メンバー変数をpublic設定する場合は読み込み専用変数や書き込み専用変数に設定ができないですが、ゲッター(getter)だけ実装すると読み込み専用、セッター(setter)だけすると書き込み専用の変数に設定することができるし、また、ログなどを設定してデバッグする時にcall stackヒストリにより参照追跡も可能です。

なので、オブジェクト指向プログラミング(OOP)ではメンバー変数をpublicを設定することではなく、privateに設定してゲッターやセッターにより設定、取得するように実装します。


C#ではJavaとは違い、ゲッターとセッターを文法的に実装することがありますが、それがプロパティ(Property)です。

using System;
 
namespace Example
{
  // クラス
  class Program
  {
    // メンバー変数
    private int data;
 
    // メンバー変数dataのプロパティ
    public int Data
    {
      // getterみたいな取得関数
      get
      {
        return this.data;
      }
      // setterみたいな設定関数
      set
      {
        // 設定パラメータはvalueのキーワードを使う。
        this.data = value;
      }
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // インスタンス生成
      Program p = new Program();
      // Programのインスタンスのメンバー変数のdataを設定
      p.Data = 10;
      // Programのメンバー変数を取得してコンソールに出力
      Console.WriteLine("p - data = " + p.Data);
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


普通、メンバー変数はすべて小文字で作成して、プロパティはその変数名から始めの文字だけ大文字に設定します。その後、プロパティのデータタイプによりゲッターのリターンタイプが設定されるし、セッターのパラメータのデータタイプが設定されます。

スタック領域の中で実装するのは、getの場合はgetterと似ているし、setの場合はsetterと似ているように実装します。

ここでも、setキーワード無しでgetだけ実装すると読み込み専用になるし、getキーワード無しでsetだけ実装すると書き込み専用になります。

using System;
 
namespace Example
{
  // クラス
  class Program
  {
    // メンバー変数
    private int data;
 
    // メンバー変数dataのプロパティ
    public int Data
    {
      // getterみたいな取得関数
      get
      {
        return this.data;
      }
      // setを除いて読み込み専用に設定
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // インスタンス生成
      Program p = new Program();
      // Programのインスタンスのメンバー変数のdataを設定
      p.Data = 10;
      // Programのメンバー変数を取得してコンソールに出力
      Console.WriteLine("p - data = " + p.Data);
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


そしてプロパティのアクセス修飾子は基本的にgetのアクセス修飾子です。つまり、getとsetのアクセス修飾子を別に設定することができます。

using System;
 
namespace Example
{
  // クラス
  class Program
  {
    // メンバー変数
    private int data;
    // コンストラクタでメンバー変数を設定
    public Program()
    {
      // プロパティを通ってメンバー変数を設定
      this.Data = 10;
    }
 
    // メンバー変数dataのプロパティ
    public int Data
    {
      // getterみたいな取得関数
      get
      {
        return this.data;
      }
      // setterと同じ設定関数、アクセス修飾子を内部と継承するクラスだけ設定できるように設定
      protected set
      {
        // 設定パラメータはvalueのキーワードを使う。
        this.data = value;
      }
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // インスタンス生成
      Program p = new Program();
      // Programのメンバー変数を取得してコンソールに出力
      Console.WriteLine("p - data = " + p.Data);
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


上のソースはDataのプロパティでsetだけアクセス修飾子を別に設定しました。


プロパティの役はメンバー変数の制御です。オブジェクト指向プログラミングではメンバー変数がprivateに固定になります。

なので、オブジェクト指向プログラミングではメンバー変数がクラス内部ではアクセスすることができますが、プロパティがあるところでオブジェクトタイプのクラスを実装することではメンバー変数が意味があるでしょう?

なので、C#ではプロパティを設定するとメンバー変数を省略することができます。

using System;
 
namespace Example
{
  // クラス
  class Program
  {
    // メンバー変数
    private int data;
    // コンストラクタでメンバー変数を設定
    public Program()
    {
      // プロパティを通ってメンバー変数を設定
      this.Data = 10;
    }
 
    // メンバー変数dataのプロパティ
    public int Data
    {
      // メンバー変数が省略すると、get、setを下記通りに設定することが可能(ビルドした後の内部には変数がある。)
      // get、setの特別な制御式を必要ならメンバー変数が必要
      get; protected set;
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // インスタンス生成
      Program p = new Program();
      // Programのメンバー変数を取得してコンソールに出力
      Console.WriteLine("p - data = " + p.Data);
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


上のソースではメンバー変数を省略しました。そしてプロパティの実装する部分みるとスタック領域を省略してget;set;キーワードだけあります。setの場合は別にアクセス修飾子も設定しました。

プロパティだけ使うことでメンバー変数がないことではありません。Classのリフレクション(Reflection)でクラス内部をみると変数があることを確認できます。

using System;
using System.Reflection;
 
namespace Example
{
  // クラス
  class Program
  {
    // プロパティ(メンバー変数がない)
    public int Data
    {
      get; set;
    }
 
    // 実行関数
    public static void Main(string[] args)
    {
      // インスタンス生成
      Program p = new Program();
      // Reflectionでメンバー変数のリストを取得
      foreach (var field in p.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic))
      {
        // コンソール出力
        Console.WriteLine(field.Name);
      }
 
      // 任意のキーを押してください
      Console.WriteLine("Press any key...");
      Console.ReadLine();
    }
  }
}


ソース上でProgramクラスはDataのプロパティだけありますが、リフレクション(Reflection)でクラスを確認するとメンバー変数があることで表示されます。


ここまでC#のプロパティ(Property)に関する説明でした。


ご不明なところや間違いところがあればコメントしてください。

#C#
最新投稿