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

プロパティは、プライベート フィールドの値の読み取り、書き込み、または計算を行う、柔軟な機構が用意されたメンバーです。 プロパティは、パブリック データのメンバーのように使用できますが、"アクセサー" という特殊なメソッドです。 この特徴によって、メソッドの安全性と柔軟性を高めながら、簡単にデータにアクセスできます。

プロパティの概要

  • プロパティを使えば、実装や検査コードを隠したままで、値の取得と設定についてパブリックな方法をクラスが公開できます。
  • get プロパティ アクセサーはプロパティ値を取得するために使用し、set プロパティ アクセサーは新しい値を割り当てるために使用します。 オブジェクトの構築時にのみ、init プロパティ アクセサーを使用して新しい値が割り当てられます。 これらのアクセサーには異なるアクセス レベルを指定できます。 詳細については、「アクセサーのアクセシビリティの制限」を参照してください。
  • set または init アクセサーで割り当てる値は value キーワードを使用して定義します。
  • プロパティの種類には、読み取り/書き込み (get アクセサーと set アクセサーの両方を備える)、読み取り専用 (get アクセサーのみで set アクセサーはない)、書き込み専用 (set アクセサーのみで get アクセサーはない) があります。 書き込み専用のプロパティの使用頻度は低く、ほとんどの場合、機密データへのアクセスを制限するために使用されます。
  • カスタムのアクセサー コードを必要としない単純なプロパティは、式本体の定義として、または自動実装プロパティとして実装できます。

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

プロパティを実装する基本的な手法の 1 つとして、プロパティ値の設定と取得にプライベート バッキング フィールドを使用する方法があります。 この方法では、get アクセサーはプライベート フィールドの値を返します。set アクセサーはプライベート フィールドに値を割り当てる前にデータ検証を実行できます。 また、どちらのアクセサーも、データの変換や計算を行ってから、データを格納したり返したりすることができます。

このパターンを説明する例を下に示します。 この例では、TimePeriod クラスは時間間隔を表しています。 クラスの内部では、_seconds という名前のプライベート フィールドに時間間隔が秒単位で格納されます。 Hours という読み取り/書き込みプロパティでは、ユーザーが時間間隔を時間単位で指定できます。 get アクセサーと set アクセサーの両方で、必要に応じて時間と秒の変換が実行されます。 また、set アクセサーは、データを検証し、時間数が無効である場合に ArgumentOutOfRangeException をスローします。

public class TimePeriod
{
    private double _seconds;

    public double Hours
    {
        get { return _seconds / 3600; }
        set
        {
            if (value < 0 || value > 24)
                throw new ArgumentOutOfRangeException(nameof(value),
                      "The valid range is between 0 and 24.");

            _seconds = value * 3600;
        }
    }
}

次の例に示すように、プロパティにアクセスして値を取得し、設定できます。

TimePeriod t = new TimePeriod();
// The property assignment causes the 'set' accessor to be called.
t.Hours = 24;

// Retrieving the property causes the 'get' accessor to be called.
Console.WriteLine($"Time in hours: {t.Hours}");
// The example displays the following output:
//    Time in hours: 24

式本体の定義

プロパティ アクセサーは、通常、式の結果を割り当てるか返すだけの 1 行のステートメントで構成されます。 プロパティは、本体が式形式のメンバーとして実装できます。 式本体の定義は、=> 記号の後に、プロパティに割り当てるかプロパティから取得するための式を続けて構成します。

読み取り専用プロパティに get アクセサーを式形式のメンバーとして実装できます。 この場合、get アクセサー キーワードと return キーワードはどちらも使用しません。 次の例では、読み取り専用 Name プロパティを式形式のメンバーとして実装しています。

public class Person
{
    private string _firstName;
    private string _lastName;

    public Person(string first, string last)
    {
        _firstName = first;
        _lastName = last;
    }

    public string Name => $"{_firstName} {_lastName}";
}

getset のアクセサーのどちらも、式形式のメンバーとして実装できます。 この場合、get キーワードと set キーワードを使用する必要があります。 両方のアクセサーに式本体の定義を使用する例を次に示します。 return キーワードは get アクセサーでは使用されません。

public class SaleItem
{
    string _name;
    decimal _cost;

    public SaleItem(string name, decimal cost)
    {
        _name = name;
        _cost = cost;
    }

    public string Name
    {
        get => _name;
        set => _name = value;
    }

    public decimal Price
    {
        get => _cost;
        set => _cost = value;
    }
}

自動実装プロパティ

ロジックを追加しなくても、プロパティの get アクセサーと set アクセサーはバッキング フィールドに値を割り当てたり、バッキング フィールドから取得したりできます。 この自動実装プロパティを使用すると、C# コンパイラによってバッキング フィールドが透過的に提供されるため、コードを簡略化できます。

プロパティに getset (または getinit) の両方のアクセサーがある場合は、どちらも自動実装する必要があります。 自動実装プロパティを定義するには、実装を省略して get キーワードと set キーワードを使用します。 次の例は前の例と似ていますが、NamePrice が自動実装プロパティである点が異なります。 この例では、パラメーター化されたコンストラクターも削除されているため、SaleItem オブジェクトがパラメーターなしのコンストラクターの呼び出しとオブジェクト初期化子を使用して初期化されています。

public class SaleItem
{
    public string Name
    { get; set; }

    public decimal Price
    { get; set; }
}

自動実装プロパティでは、get アクセサーと set アクセサーに対して異なるアクセシビリティを宣言できます。 通常、パブリック get アクセサーとプライベート set アクセサーを宣言します。 詳細は、アクセサー アクセシビリティの制限に関する記事で確認できます。

必須プロパティ

C# 11 以降で、任意のプロパティまたはフィールドを初期化するようにクライアント コードを強制する required メンバーを追加できます。

public class SaleItem
{
    public required string Name
    { get; set; }

    public required decimal Price
    { get; set; }
}

SaleItem を作成するには、次のコードのように、オブジェクト初期化子を利用して Name プロパティと Price プロパティの両方を設定する必要があります。

var item = new SaleItem { Name = "Shoes", Price = 19.95m };
Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");

C# 言語仕様

詳細については、「C# 言語の仕様」のプロパティに関するセクションを参照してください。 言語仕様は、C# の構文と使用法に関する信頼性のある情報源です。

こちらもご覧ください