プロパティの使用 (C# プログラミング ガイド)

プロパティは、フィールドとメソッドの両方の側面を結合します。 オブジェクトのユーザーにとってプロパティは、プロパティへのアクセスに同じ構文を必要とするフィールドのように見えます。 クラスの実装者にとってプロパティは、get アクセサーと set アクセサーの両方またはいずれかを表す 1 つまたは 2 つのコード ブロックです。 get アクセサーのコード ブロックはプロパティが読み取られる時に実行され、set アクセサーのコード ブロックはプロパティに新しい値が割り当てられるときに実行されます。 set アクセサーのないプロパティは読み取り専用と見なされます。 get アクセサーのないプロパティは書き込み専用と見なされます。 両方のアクセサーを持つプロパティは、読み取り/書き込みです。

フィールドとは異なり、プロパティは変数には分類されません。 そのため、プロパティを ref または out パラメーターとして渡すことはできません。

プロパティには次のようなさまざまな用途があります。変更を許可する前にデータを検証したり、データをそのデータが実際に他のソース (データベースなど) から取得されるクラスで透過的に公開したり、イベントの発生や他のフィールドの値を変更するなど、データが変更されたときに、アクションを実行したりすることができます。

プロパティはクラス ブロックで宣言できます。フィールドのアクセス レベル、プロパティの型、プロパティの名前、get アクセサーと set アクセサーの両方またはいずれかを宣言するコード ブロックの順で指定します。 例:

public class Date
{
    private int month = 7;  // Backing store

    public int Month
    {
        get
        {
            return month;
        }
        set
        {
            if ((value > 0) && (value < 13))
            {
                month = value;
            }
        }
    }
}

この例では、set アクセサーが Month が 1 から 12 までの値に設定されていることを確認できるように、Month がプロパティとして宣言されています。 Month プロパティは、プライベート フィールドを使用して実際の値を追跡します。 プロパティのデータの実際の場所は、プロパティの "バッキング ストア" と呼ばれることがよくあります。 プロパティがプライベート フィールドをバッキング ストアとして使用するのは一般的なことです。 フィールドは、プロパティを呼び出すことでのみ変更できるようにするため、プライベートとマークされます。 パブリックおよびプライベートのアクセス制限の詳細については、「アクセス修飾子」を参照してください。

自動実装プロパティは、単純なプロパティ宣言の簡単な構文を提供します。 詳細については、「自動実装プロパティ」を参照してください。

get アクセサー

get アクセサーの本体は、メソッドの本体と似ています。 プロパティの型の値を返す必要があります。 get アクセサーの実行は、フィールドの値を読み取ることに相当します。 たとえば、get アクセサーからプライベート変数を返し、最適化が有効になっている場合、get アクセサー メソッドへの呼び出しはコンパイラによってインライン化されるため、メソッド呼び出しのオーバーヘッドはありません。 ただし、仮想 get アクセサー メソッドはインライン化できません。これは、コンパイラがコンパイル時にどのメソッドが実際に実行時に呼び出されるかを認識しないからです。 次に、プライベート フィールド name の値を返す get アクセサーを示します。

class Person
{
    private string name;  // the name field
    public string Name    // the Name property
    {
        get
        {
            return name;
        }
    }
}

プロパティを参照するとき、割り当ての対象を除き、get アクセサーがプロパティの値を読み取るために呼び出されます。 例:

Person person = new Person();
//...

System.Console.Write(person.Name);  // the get accessor is invoked here

get アクセサーは return または throw ステートメントで終わる必要があります。コントロールはアクセサー本体をフロー オフすることはできません。

get アクセサーを使用してオブジェクトの状態を変更するのは、悪いプログラミング スタイルです。 たとえば、次のアクセサーでは、number フィールドにアクセスされるたびにオブジェクトの状態が変更される副作用が発生します。

private int number;
public int Number
{
    get
    {
        return number++;   // Don't do this
    }
}

get アクセサーは、フィールド値を返すまたは計算してから返すために使用できます。 例:

class Employee
{
    private string name;
    public string Name
    {
        get
        {
            return name != null ? name : "NA";
        }
    }
}

前のコード セグメントで Name プロパティに値を割り当てない場合、値 NA が返されます。

set アクセサー

set アクセサーは、戻り値の型が void のメソッドと似ています。 型がプロパティの型の value と呼ばれる暗黙のパラメーターを使用します。 次の例では、set アクセサーが Name プロパティに追加されます。

class Person
{
    private string name;  // the name field
    public string Name    // the Name property
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }
}

プロパティに値を割り当てるときに、新しい値を提供する引数を使用して set アクセサーが呼び出されます。 例:

Person person = new Person();
person.Name = "Joe";  // the set accessor is invoked here                

System.Console.Write(person.Name);  // the get accessor is invoked here

set アクセサーでローカル変数の宣言に暗黙のパラメーター名 value を使用すると、エラーになります。

コメント

プロパティはpublicprivateprotectedinternal、または protected internal のいずれかでマークされます。 これらのアクセス修飾子により、クラスのユーザーがプロパティにアクセスできる方法が定義されます。 同じプロパティの getset アクセサーは、異なるアクセス修飾子を持つことができます。 たとえば、getpublic にして、型の外部からの読み取り専用アクセスを許可して、setprivate または protected にすることができます。 詳細については、「アクセス修飾子」を参照してください。

static キーワードを使用して、プロパティを静的プロパティとして宣言できます。 その場合、クラスのインスタンスが存在しなくても、呼び出し元がいつでもプロパティを使用できるようになります。 詳細については、「静的クラスと静的クラス メンバー」を参照してください。

プロパティは、virtual キーワードを使用して仮想プロパティとしてマークできます。 その場合、派生クラスでは、override キーワードを使用してプロパティの動作をオーバーライドできます。 これらのオプションの詳細については、「継承」を参照してください。

仮想プロパティをオーバーライドするプロパティは、sealed にすることもできます。その場合、派生クラスでは、プロパティが仮想でなくなります。 最後に、プロパティは抽象として宣言できます。 つまり、クラスに実装はなく、派生クラスが独自の実装を記述する必要があります。 これらのオプションの詳細については、「抽象クラスとシール クラス、およびクラス メンバー」を参照してください。

注意

静的プロパティのアクセサーでvirtualabstract、または override 修飾子を使用すると、エラーになります。

この例では、インスタンス、静的、および読み取り専用のプロパティを示します。 キーボードから従業員の名前を受け取り、NumberOfEmployees を 1 だけインクリメントし、従業員の名前と番号を表示します。

public class Employee
{
    public static int NumberOfEmployees;
    private static int counter;
    private string name;

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

    // A read-only static property:
    public static int Counter
    {
        get { return counter; }
    }

    // A Constructor:
    public Employee()
    {
        // Calculate the employee's number:
        counter = ++counter + NumberOfEmployees;
    }
}

class TestEmployee
{
    static void Main()
    {
        Employee.NumberOfEmployees = 107;
        Employee e1 = new Employee();
        e1.Name = "Claude Vige";

        System.Console.WriteLine("Employee number: {0}", Employee.Counter);
        System.Console.WriteLine("Employee name: {0}", e1.Name);
    }
}
/* Output:
    Employee number: 108
    Employee name: Claude Vige
*/

この例では、派生クラスで同じ名前を持つ別のプロパティによって非表示にされている基底クラスのプロパティにアクセスする方法を示します。

public class Employee
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}

public class Manager : Employee
{
    private string name;

    // Notice the use of the new modifier:
    public new string Name
    {
        get { return name; }
        set { name = value + ", Manager"; }
    }
}

class TestHiding
{
    static void Main()
    {
        Manager m1 = new Manager();

        // Derived class property.
        m1.Name = "John";

        // Base class property.
        ((Employee)m1).Name = "Mary";

        System.Console.WriteLine("Name in the derived class is: {0}", m1.Name);
        System.Console.WriteLine("Name in the base class is: {0}", ((Employee)m1).Name);
    }
}
/* Output:
    Name in the derived class is: John, Manager
    Name in the base class is: Mary
*/

前の例で重要な点を次に示します。

  • 派生クラスのプロパティ Name により基底クラス内のプロパティ Name が非表示になっています。 このような場合、new 修飾子は派生クラスのプロパティの宣言で使用されます。

    public new string Name
    
  • キャスト (Employee) は基底クラスで非表示のプロパティにアクセスするために使用されます。

    ((Employee)m1).Name = "Mary";
    

    メンバーを非表示にする詳細については、「new 修飾子」を参照してください。

この例では、CubeSquare の 2 つのクラスが抽象クラス Shape を実装し、その抽象 Area プロパティを上書きします。 プロパティでの override 修飾子の使用に注意してください。 プログラムは、入力として辺を受け入れ、四角形と立方体の面積を計算します。 プログラムはまた、入力として面積を受け入れ、四角形と立方体の対応する辺を計算します。

abstract class Shape
{
    public abstract double Area
    {
        get;
        set;
    }
}

class Square : Shape
{
    public double side;

    public Square(double s)  //constructor
    {
        side = s;
    }

    public override double Area
    {
        get
        {
            return side * side;
        }
        set
        {
            side = System.Math.Sqrt(value);
        }
    }
}

class Cube : Shape
{
    public double side;

    public Cube(double s)
    {
        side = s;
    }

    public override double Area
    {
        get
        {
            return 6 * side * side;
        }
        set
        {
            side = System.Math.Sqrt(value / 6);
        }
    }
}

class TestShapes
{
    static void Main()
    {
        // Input the side:
        System.Console.Write("Enter the side: ");
        double side = double.Parse(System.Console.ReadLine());

        // Compute the areas:
        Square s = new Square(side);
        Cube c = new Cube(side);

        // Display the results:
        System.Console.WriteLine("Area of the square = {0:F2}", s.Area);
        System.Console.WriteLine("Area of the cube = {0:F2}", c.Area);
        System.Console.WriteLine();

        // Input the area:
        System.Console.Write("Enter the area: ");
        double area = double.Parse(System.Console.ReadLine());

        // Compute the sides:
        s.Area = area;
        c.Area = area;

        // Display the results:
        System.Console.WriteLine("Side of the square = {0:F2}", s.side);
        System.Console.WriteLine("Side of the cube = {0:F2}", c.side);
    }
}
/* Example Output:
    Enter the side: 4
    Area of the square = 16.00
    Area of the cube = 96.00

    Enter the area: 24
    Side of the square = 4.90
    Side of the cube = 2.00
*/

関連項目

C# プログラミング ガイド
プロパティ
インターフェイスのプロパティ
自動実装プロパティ