csharp propertyとは?C#プロパティのget/set・フィールドとの違い・自動実装を初心者向けに解説

はじめに

C#を学び始めると、クラスの中でよく登場するのが「プロパティ」です。

C#
public string Name { get; set; }
public int Age { get; set; }

このような書き方を見て、「これは変数なの?」「getやsetは何をしているの?」「フィールドとの違いは?」と疑問に感じる人は多いです。

C#のプロパティは、クラスのデータを外部から安全に扱うための重要な仕組みです。特に、csharp propertyや「C# property」と検索している人は、フィールド・get/set・自動実装プロパティの違いでつまずいていることが多いでしょう。

この記事では、C#プロパティの基本から、get/setの意味、フィールドとの違い、自動実装プロパティ、読み取り専用プロパティ、実践的な使い方まで、初心者向けに順番に解説します。

1. csharp propertyとは?C#プロパティの基本を初心者向けに解説

1-1. C#のpropertyは「フィールドへのアクセスを制御する仕組み」

C#のプロパティとは、クラスが持つ値を外部から取得したり、変更したりするための仕組みです。

たとえば、次のようなクラスがあるとします。

C#
public class Person
{
public string Name { get; set; }
}

このNameがプロパティです。

外部のコードからは、次のように変数のような感覚で使えます。

C#
Person person = new Person();

person.Name = "Taro";
Console.WriteLine(person.Name);

見た目は普通の変数のようですが、実際にはgetsetという仕組みを通して値を取得・代入しています。

プロパティの大きな役割は、クラス内部のデータを直接公開するのではなく、必要に応じて制御しながら公開することです。

1-2. プロパティが使われる場面

C#プロパティは、クラスの状態や情報を表すときによく使われます。

たとえば、ユーザー情報を表すクラスでは次のようなプロパティが考えられます。

C#
public class User
{
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}

商品を表すクラスなら、次のようになります。

C#
public class Product
{
public string Name { get; set; }
public int Price { get; set; }
public bool IsAvailable { get; set; }
}

このように、プロパティは「そのオブジェクトが持つ情報」を表すために使われます。

また、値をそのまま持つだけでなく、代入時にチェックしたり、取得時に計算した値を返したりすることもできます。

1-3. プロパティ・フィールド・メソッドの関係をざっくり理解する

C#のクラスには、主にフィールド、プロパティ、メソッドがあります。

フィールドは、クラス内部で値を保存するための変数です。

C#
private string name;

プロパティは、その値を外部から取得・変更するための入口です。

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

メソッドは、何らかの処理を実行するためのものです。

C#
public void SayHello()
{
Console.WriteLine("Hello");
}

ざっくり言うと、フィールドは「データの置き場所」、プロパティは「データへの窓口」、メソッドは「処理を実行するもの」です。

C#では、外部から直接フィールドを触らせるのではなく、プロパティを通して値を扱う設計がよく使われます。

2. C#プロパティの基本構文:get/setの書き方

2-1. getアクセサとは?値を取得する仕組み

getアクセサは、プロパティの値を取得するときに呼び出される部分です。

C#
private string name;

public string Name
{
get
{
return name;
}
}

この場合、外部からNameを読み取ると、getの中の処理が実行されます。

C#
Console.WriteLine(person.Name);

このコードでは、Nameプロパティのgetが呼ばれ、内部のnameフィールドの値が返されます。

つまり、getは「このプロパティが読み取られたときに、どの値を返すか」を決める場所です。

2-2. setアクセサとは?値を代入する仕組み

setアクセサは、プロパティに値を代入するときに呼び出される部分です。

C#
private string name;

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

外部から次のように代入すると、setの中の処理が実行されます。

C#
person.Name = "Taro";

このとき、"Taro"という値がsetアクセサに渡され、内部のnameフィールドに代入されます。

setは「このプロパティに値が代入されたとき、どう処理するか」を決める場所です。

2-3. valueキーワードの意味と使い方

setアクセサの中で使われるvalueは、代入された値を表す特別なキーワードです。

C#
public string Name
{
set
{
name = value;
}
}

たとえば、次のように代入した場合を考えます。

C#
person.Name = "Hanako";

このとき、valueには"Hanako"が入ります。

つまり、次のようなイメージです。

C#
name = "Hanako";

valueは自分で宣言する必要はありません。setアクセサの中で自動的に使えるキーワードです。

入力チェックをしたい場合にも、valueを使います。

C#
public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
throw new ArgumentException("年齢は0以上で入力してください。");
}

age = value;
}
}

この例では、代入された値が0未満なら例外を投げ、正しい値だけをフィールドに保存しています。

2-4. 最小構成のプロパティ例

C#プロパティの最もシンプルな形は、次のような自動実装プロパティです。

C#
public string Name { get; set; }

これは、値の取得と代入ができるプロパティです。

C#
Person person = new Person();

person.Name = "Taro";
Console.WriteLine(person.Name);

初心者のうちは、まずこの形を覚えるとよいでしょう。

ただし、入力チェックをしたい場合や、値の取得・代入時に特別な処理をしたい場合は、次のように通常のプロパティとして書きます。

C#
private string name;

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

3. フィールドとの違い:なぜpublicフィールドではなくプロパティを使うのか

3-1. フィールドとは何か

フィールドとは、クラスの中に定義する変数のことです。

C#
public class Person
{
private string name;
private int age;
}

このnameageがフィールドです。

フィールドは、クラス内部でデータを保存するために使われます。多くの場合、フィールドはprivateにして外部から直接アクセスできないようにします。

一方で、次のようにpublicフィールドとして公開することもできます。

C#
public class Person
{
public string name;
}

この場合、外部から直接値を読み書きできます。

C#
person.name = "Taro";

ただし、C#ではこのようなpublicフィールドはあまり推奨されません。

3-2. プロパティとフィールドの見た目・役割の違い

フィールドとプロパティは、使う側から見ると似ています。

C#
person.Name = "Taro";
Console.WriteLine(person.Name);

しかし、内部的な役割は異なります。

フィールドは、値を直接保存する場所です。

C#
public string Name;

プロパティは、値へのアクセスを制御する窓口です。

C#
public string Name { get; set; }

自動実装プロパティの場合、見た目はフィールドに近いですが、実際にはプロパティです。コンパイラが内部的にバッキングフィールドを用意し、getsetを通して値を扱います。

つまり、フィールドは「データそのもの」、プロパティは「データを扱うための入口」と考えると理解しやすいです。

3-3. カプセル化とデータ保護の観点での違い

プロパティを使う大きな理由の1つが、カプセル化です。

カプセル化とは、クラス内部のデータを外部から直接触らせず、必要な操作だけを公開する考え方です。

たとえば、年齢を表すAgeにマイナスの値が入ると困ります。

publicフィールドの場合、次のような代入ができてしまいます。

C#
person.Age = -10;

もしAgeがpublicフィールドなら、この不正な値を防ぐ仕組みがありません。

一方、プロパティならsetでチェックできます。

C#
private int age;

public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
throw new ArgumentException("年齢は0以上である必要があります。");
}

age = value;
}
}

このように、プロパティを使えば、外部からのアクセスを許可しつつ、不正な値を防ぐことができます。

3-4. 後から処理を追加しやすいというメリット

最初は単純に値を保存するだけでも、後から入力チェックやログ出力などの処理を追加したくなることがあります。

たとえば、最初は次のような自動実装プロパティだったとします。

C#
public int Price { get; set; }

後から「価格は0以上にしたい」となった場合、通常のプロパティに変更できます。

C#
private int price;

public int Price
{
get
{
return price;
}
set
{
if (value < 0)
{
throw new ArgumentException("価格は0以上で入力してください。");
}

price = value;
}
}

使う側のコードは、基本的にそのままです。

C#
product.Price = 1000;

このように、プロパティを使っておくと、後から内部処理を追加しやすくなります。

publicフィールドを使っていると、後からプロパティに変更したときに影響が出る場合があります。そのため、外部に公開する値は、基本的にプロパティとして定義するのが一般的です。

4. バッキングフィールドを使った通常のプロパティ

4-1. privateフィールドとpublicプロパティの基本形

通常のプロパティでは、値を保存するためのprivateフィールドを用意し、それをpublicプロパティから操作します。

C#
public class Person
{
private string name;

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

このnameのように、プロパティの裏側で値を保存するフィールドをバッキングフィールドと呼びます。

外部からはNameプロパティを使います。

C#
Person person = new Person();
person.Name = "Taro";

Console.WriteLine(person.Name);

クラスの外側からnameフィールドへ直接アクセスすることはできません。

C#
// person.name = "Taro"; // privateなので外部からは使えない

このように、内部のデータはprivateフィールドに隠し、外部にはpublicプロパティを公開するのが基本形です。

4-2. getでフィールドの値を返す流れ

getアクセサは、バッキングフィールドの値を返すために使います。

C#
public string Name
{
get
{
return name;
}
}

外部で次のように書くと、

C#
Console.WriteLine(person.Name);

内部ではgetが呼び出され、nameフィールドの値が返されます。

つまり、処理の流れは次のようになります。

  1. person.Nameが読み取られる

  2. Nameプロパティのgetが呼ばれる

  3. nameフィールドの値が返される

  4. 返された値が表示される

プロパティを使う側は、メソッド呼び出しのように書く必要はありません。変数のように自然に読み取れるのが特徴です。

4-3. setで入力値をチェックして代入する流れ

setアクセサでは、代入された値を受け取り、必要に応じてチェックしてからフィールドに保存します。

C#
private int age;

public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
throw new ArgumentException("年齢は0以上で入力してください。");
}

age = value;
}
}

次のように代入すると、

C#
person.Age = 20;

内部ではsetが呼ばれ、valueには20が入ります。

処理の流れは次のようになります。

  1. person.Age = 20が実行される

  2. Ageプロパティのsetが呼ばれる

  3. value20が入る

  4. value < 0かどうかを確認する

  5. 問題なければageフィールドに代入する

不正な値を防ぎたいときは、このようにsetにチェック処理を書きます。

4-4. 年齢・名前などの入力チェック例

年齢や名前は、入力チェックの例としてよく使われます。

まず、年齢のチェックです。

C#
public class Person
{
private int age;

public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
throw new ArgumentException("年齢は0以上で入力してください。");
}

age = value;
}
}
}

次に、名前が空文字やnullにならないようにする例です。

C#
public class Person
{
private string name;

public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は必須です。");
}

name = value;
}
}
}

このように、プロパティを使うと、オブジェクトが不正な状態になることを防ぎやすくなります。

クラスを安全に使ってもらうためには、必要なチェックをプロパティやコンストラクタに入れることが大切です。

5. 自動実装プロパティとは?{ get; set; }をシンプルに理解する

5-1. 自動実装プロパティの基本構文

自動実装プロパティとは、バッキングフィールドを自分で書かずに定義できるプロパティです。

C#
public string Name { get; set; }
public int Age { get; set; }

この書き方は、C#で非常によく使われます。

通常のプロパティでは、次のようにprivateフィールドとget/setを書きます。

C#
private string name;

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

しかし、特別な処理が不要な場合は、毎回このように書くのは少し冗長です。

そこで、自動実装プロパティを使います。

C#
public string Name { get; set; }

これだけで、値の取得と代入ができるプロパティになります。

5-2. コンパイラが自動でバッキングフィールドを作る仕組み

自動実装プロパティでは、コード上にはバッキングフィールドが見えません。

C#
public string Name { get; set; }

しかし、内部的にはコンパイラが値を保存するためのフィールドを自動で用意しています。

つまり、イメージとしては次のような通常のプロパティに近いものです。

C#
private string name;

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

ただし、自動生成されたバッキングフィールドには、通常のコードから直接アクセスできません。

そのため、自動実装プロパティでは、getsetの中に独自の処理を書くことはできません。

5-3. 通常のプロパティとの違い

通常のプロパティと自動実装プロパティの違いは、処理を自分で書けるかどうかです。

自動実装プロパティはシンプルです。

C#
public int Age { get; set; }

ただし、代入時のチェックは書けません。

C#
// この形では、Ageにマイナス値が入ることを防げない
public int Age { get; set; }

一方、通常のプロパティなら、setの中にチェックを書けます。

C#
private int age;

public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
throw new ArgumentException("年齢は0以上で入力してください。");
}

age = value;
}
}

特別な処理が不要なら自動実装プロパティ、チェックや変換が必要なら通常のプロパティ、と考えるとわかりやすいです。

5-4. 自動実装プロパティを使うべきケース

自動実装プロパティは、単純に値を保持したい場合に向いています。

たとえば、DTOや設定値、画面表示用のデータなどではよく使われます。

C#
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}

このようなクラスでは、値をそのまま受け渡しすることが目的なので、自動実装プロパティで十分なことが多いです。

また、あとから必要になれば通常のプロパティに変更することもできます。

C#
private string name;

public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は必須です。");
}

name = value;
}
}

最初からすべてを複雑に書く必要はありません。まずは自動実装プロパティで始め、必要になったら通常のプロパティに変えるという考え方が実用的です。

5-5. 自動実装プロパティを使わない方がよいケース

自動実装プロパティを使わない方がよいのは、値の代入や取得に何らかの制御が必要な場合です。

たとえば、次のようなケースです。

  • マイナス値を禁止したい

  • nullや空文字を禁止したい

  • 代入時に文字列を整形したい

  • 値が変更されたときに通知したい

  • 取得時に別の値から計算したい

たとえば、名前の前後の空白を取り除いて保存したい場合、自動実装プロパティでは対応できません。

C#
private string name;

public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は必須です。");
}

name = value.Trim();
}
}

このように、何か処理を挟みたいときは、バッキングフィールドを持つ通常のプロパティを使います。

6. 読み取り専用・書き込み制限のあるプロパティ

6-1. getのみの読み取り専用プロパティ

プロパティは、必ずしもgetsetの両方を持つ必要はありません。

getだけのプロパティにすると、外部から読み取りはできますが、代入はできません。

C#
public class Person
{
public string Name { get; }

public Person(string name)
{
Name = name;
}
}

この場合、Nameはコンストラクタで設定され、その後は変更できません。

C#
Person person = new Person("Taro");

Console.WriteLine(person.Name);

// person.Name = "Hanako"; // エラー

読み取り専用プロパティは、一度決めたら変えたくない値に使います。

たとえば、ID、作成日時、初期化時に決まる名前などです。

C#
public class User
{
public int Id { get; }
public DateTime CreatedAt { get; }

public User(int id)
{
Id = id;
CreatedAt = DateTime.Now;
}
}

6-2. private setで外部からの変更を防ぐ

private setを使うと、外部からは読み取りだけを許可し、クラス内部からだけ変更できるプロパティを作れます。

C#
public class User
{
public string Name { get; private set; }

public User(string name)
{
Name = name;
}

public void ChangeName(string newName)
{
if (string.IsNullOrWhiteSpace(newName))
{
throw new ArgumentException("名前は必須です。");
}

Name = newName;
}
}

外部からは次のように読み取れます。

C#
Console.WriteLine(user.Name);

しかし、外部から直接代入することはできません。

C#
// user.Name = "Hanako"; // エラー

名前を変更したい場合は、ChangeNameメソッドを通す必要があります。

C#
user.ChangeName("Hanako");

このようにすると、値の変更ルールをクラス内に集めることができます。

6-3. initアクセサで初期化時だけ代入を許可する

initアクセサを使うと、オブジェクトの初期化時だけ値を代入できるプロパティを作れます。

C#
public class User
{
public string Name { get; init; }
public string Email { get; init; }
}

オブジェクト初期化子を使って、次のように代入できます。

C#
User user = new User
{
Name = "Taro",
Email = "taro@example.com"
};

しかし、初期化後に変更することはできません。

C#
// user.Name = "Hanako"; // エラー

initは、初期化時に値を設定したいが、その後は変更されたくない場合に便利です。

読み取り専用に近い性質を持ちながら、オブジェクト初期化子で書きやすいというメリットがあります。

6-4. setを公開しすぎると起きる問題

すべてのプロパティを何でもpublic setにしてしまうと、外部から自由に値を書き換えられてしまいます。

C#
public class Order
{
public int Id { get; set; }
public int TotalPrice { get; set; }
public bool IsPaid { get; set; }
}

このような設計では、外部コードから不自然な変更ができてしまいます。

C#
order.TotalPrice = -1000;
order.IsPaid = true;

本来、合計金額は注文内容から計算されるべきかもしれません。また、支払い状態は決済処理が成功したときだけ変更されるべきかもしれません。

そのような値まで自由に変更できると、オブジェクトの状態が壊れやすくなります。

必要がない限り、setをむやみに公開しないことが大切です。

C#
public class Order
{
public int Id { get; }
public int TotalPrice { get; private set; }
public bool IsPaid { get; private set; }

public void MarkAsPaid()
{
IsPaid = true;
}
}

このように、変更できる場所を制限すると、安全なクラス設計になります。

7. C#プロパティの実践的な使い方

7-1. クラス設計でプロパティを使う基本パターン

C#でクラスを設計するときは、「外部に公開したい情報」をプロパティとして定義します。

たとえば、社員を表すクラスなら次のようになります。

C#
public class Employee
{
public int Id { get; }
public string Name { get; private set; }
public int Age { get; private set; }

public Employee(int id, string name, int age)
{
Id = id;
Name = name;
Age = age;
}
}

この例では、Idは読み取り専用、NameAgeはクラス内部から変更可能にしています。

さらに、名前や年齢を変更するためのメソッドを用意すると、ルールを守りながら値を変更できます。

C#
public void ChangeName(string newName)
{
if (string.IsNullOrWhiteSpace(newName))
{
throw new ArgumentException("名前は必須です。");
}

Name = newName;
}

プロパティは単なるデータの入れ物ではなく、クラスの使い方を表す設計要素でもあります。

7-2. コンストラクタとプロパティを組み合わせる

コンストラクタとプロパティを組み合わせると、オブジェクトを作る時点で必要な値を必ず設定できます。

C#
public class Product
{
public string Name { get; }
public int Price { get; }

public Product(string name, int price)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("商品名は必須です。");
}

if (price < 0)
{
throw new ArgumentException("価格は0以上で入力してください。");
}

Name = name;
Price = price;
}
}

このクラスでは、NamePriceはコンストラクタで設定され、その後は外部から変更できません。

C#
Product product = new Product("ノートPC", 120000);

Console.WriteLine(product.Name);
Console.WriteLine(product.Price);

このように、必須の値はコンストラクタで受け取り、変更したくない値はgetのみのプロパティにすると、安全な設計になります。

7-3. 計算結果を返す読み取り専用プロパティ

プロパティは、フィールドの値をそのまま返すだけではありません。計算結果を返すこともできます。

たとえば、税込価格を返すプロパティを考えます。

C#
public class Product
{
public int Price { get; set; }

public int TaxIncludedPrice
{
get
{
return (int)(Price * 1.1);
}
}
}

このTaxIncludedPriceは値を保存しているわけではなく、Priceから計算した結果を返しています。

C#
Product product = new Product();
product.Price = 1000;

Console.WriteLine(product.TaxIncludedPrice); // 1100

式形式で短く書くこともできます。

C#
public int TaxIncludedPrice => (int)(Price * 1.1);

フルネームを返すプロパティもよくある例です。

C#
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }

public string FullName => $"{LastName} {FirstName}";
}

このように、他のプロパティやフィールドから導ける値は、読み取り専用プロパティとして表現すると便利です。

7-4. プロパティ内で例外を投げるバリデーション例

プロパティのsetでは、不正な値が代入されたときに例外を投げることがあります。

C#
public class BankAccount
{
private decimal balance;

public decimal Balance
{
get
{
return balance;
}
private set
{
if (value < 0)
{
throw new InvalidOperationException("残高はマイナスにできません。");
}

balance = value;
}
}

public void Deposit(decimal amount)
{
if (amount <= 0)
{
throw new ArgumentException("入金額は0より大きい必要があります。");
}

Balance += amount;
}

public void Withdraw(decimal amount)
{
if (amount <= 0)
{
throw new ArgumentException("出金額は0より大きい必要があります。");
}

Balance -= amount;
}
}

この例では、Balancesetprivateにして、外部から直接残高を変更できないようにしています。

残高を増やすにはDeposit、減らすにはWithdrawを使います。

C#
BankAccount account = new BankAccount();

account.Deposit(1000);
account.Withdraw(300);

Console.WriteLine(account.Balance);

このように、プロパティとメソッドを組み合わせることで、正しい操作だけを許可するクラスを作れます。

8. プロパティ使用時によくある疑問とつまずき

8-1. get/setは必ず書く必要があるのか

プロパティには、必ずしもgetsetの両方を書く必要はありません。

読み取りと書き込みの両方を許可したい場合は、次のように書きます。

C#
public string Name { get; set; }

読み取りだけにしたい場合は、getだけにします。

C#
public string Name { get; }

外部からは読み取れるが、変更はクラス内部だけにしたい場合は、private setを使います。

C#
public string Name { get; private set; }

初期化時だけ代入できるようにしたい場合は、initを使います。

C#
public string Name { get; init; }

どの形を使うかは、「その値を誰が、いつ変更できるべきか」で決めます。

8-2. publicフィールドではダメなのか

publicフィールドが絶対に使えないわけではありません。

しかし、クラスの外部に公開する値としては、基本的にプロパティを使う方が安全です。

publicフィールドでは、外部から直接値を変更できてしまいます。

C#
public class Person
{
public int Age;
}

この場合、次のような不正な値も代入できます。

C#
person.Age = -10;

プロパティなら、代入時にチェックできます。

C#
private int age;

public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
throw new ArgumentException("年齢は0以上で入力してください。");
}

age = value;
}
}

また、将来的に処理を追加しやすいという点でも、プロパティの方が柔軟です。

そのため、外部に公開するデータはpublicフィールドではなく、publicプロパティとして定義するのが一般的です。

8-3. 自動実装プロパティとフィールドは同じなのか

自動実装プロパティとフィールドは、見た目が似ていても同じではありません。

自動実装プロパティは次のように書きます。

C#
public string Name { get; set; }

フィールドは次のように書きます。

C#
public string Name;

使う側から見ると、どちらも似たように扱えます。

C#
person.Name = "Taro";

しかし、自動実装プロパティはgetsetを持つプロパティです。コンパイラが内部的にバッキングフィールドを作っています。

一方、フィールドは値を直接保存する変数です。

プロパティには、後からprivate setにしたり、バリデーションを追加したりできる柔軟性があります。

C#
private string name;

public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は必須です。");
}

name = value;
}
}

そのため、見た目が似ていても、自動実装プロパティとフィールドは別物として理解しましょう。

8-4. プロパティに処理を書きすぎてもよいのか

プロパティには処理を書けますが、重すぎる処理を書くのは避けた方がよいです。

プロパティは、使う側から見ると変数のように見えます。

C#
Console.WriteLine(user.Name);

そのため、プロパティを読むだけで非常に時間のかかる処理が走ると、使う側は驚いてしまいます。

たとえば、次のような処理はプロパティよりメソッドの方が適しています。

  • データベースにアクセスする

  • 外部APIを呼び出す

  • 大量のファイルを読み込む

  • 非常に重い計算を実行する

プロパティには、軽い計算や簡単なチェック程度を入れるのが基本です。

C#
public string FullName => $"{LastName} {FirstName}";

時間がかかる処理や副作用の大きい処理は、メソッドとして表現した方がわかりやすくなります。

C#
public void LoadOrders()
{
// データベースから注文情報を読み込む
}

8-5. プロパティ名とフィールド名の命名ルール

C#では、プロパティ名にはPascalCaseを使うのが一般的です。

C#
public string FirstName { get; set; }
public int Age { get; set; }
public DateTime CreatedAt { get; set; }

PascalCaseとは、単語の先頭を大文字にする書き方です。

一方、privateフィールドには小文字始まりやアンダースコア始まりを使うことが多いです。

C#
private string name;
private int age;

または、次のようにアンダースコアを付ける書き方もよく使われます。

C#
private string _name;
private int _age;

通常のプロパティでは、次のような組み合わせになります。

C#
private string _name;

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

プロパティ名は外部から見える名前なので、意味が伝わる名前にすることが大切です。

9. C#プロパティのベストプラクティス

9-1. 基本は自動実装プロパティから始める

C#プロパティを書くときは、特別な理由がなければ自動実装プロパティから始めるのがおすすめです。

C#
public string Name { get; set; }
public int Age { get; set; }

自動実装プロパティは短く書けて、読みやすいです。

単純に値を保持するだけなら、バッキングフィールドを自分で書く必要はありません。

C#
public class Product
{
public string Name { get; set; }
public int Price { get; set; }
}

まずはシンプルに書き、必要になったら通常のプロパティに変更する方が、コードが無駄に複雑になりません。

9-2. 入力チェックが必要になったら通常のプロパティにする

代入される値をチェックしたい場合は、自動実装プロパティではなく、通常のプロパティを使います。

C#
private int price;

public int Price
{
get
{
return price;
}
set
{
if (value < 0)
{
throw new ArgumentException("価格は0以上で入力してください。");
}

price = value;
}
}

名前、年齢、価格、数量など、不正な値が入ると困るものは、プロパティやコンストラクタでチェックしましょう。

C#
private string name;

public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は必須です。");
}

name = value;
}
}

入力チェックを入れることで、オブジェクトが不正な状態になるのを防げます。

9-3. 外部から変更されたくない値はprivate setやgetのみを使う

外部から自由に変更されたくない値には、private setgetのみのプロパティを使います。

C#
public int Id { get; }
public DateTime CreatedAt { get; }
public string Status { get; private set; }

IdCreatedAtのように、一度決まったら変わらない値はgetのみにします。

C#
public class User
{
public int Id { get; }
public DateTime CreatedAt { get; }

public User(int id)
{
Id = id;
CreatedAt = DateTime.Now;
}
}

状態を外部から直接変更させたくない場合は、private setを使います。

C#
public class Order
{
public string Status { get; private set; } = "Created";

public void Complete()
{
Status = "Completed";
}
}

このようにすると、状態変更のルールをメソッド内に集めることができます。

9-4. プロパティには重すぎる処理を書かない

プロパティは、値を取得・設定するための仕組みです。

そのため、プロパティの中には重い処理を書きすぎないようにしましょう。

よい例は、軽い計算を返すプロパティです。

C#
public int TotalPrice => UnitPrice * Quantity;

注意したい例は、プロパティを読むたびに重い処理が走るケースです。

C#
public string Report
{
get
{
// 大量データの読み込みや重い集計処理
return CreateLargeReport();
}
}

このような処理は、プロパティではなくメソッドにした方が自然です。

C#
public string CreateReport()
{
return CreateLargeReport();
}

プロパティは「軽く取得できる値」に使い、処理の実行を表したい場合はメソッドを使う、と考えると設計しやすくなります。

9-5. 命名規則はPascalCaseを使う

C#のプロパティ名は、基本的にPascalCaseで書きます。

C#
public string UserName { get; set; }
public int TotalCount { get; set; }
public DateTime UpdatedAt { get; set; }

privateフィールドには、camelCaseやアンダースコア付きの名前を使うことが多いです。

C#
private string userName;
private int totalCount;

または、次のように書きます。

C#
private string _userName;
private int _totalCount;

プロパティとフィールドを組み合わせる場合は、名前の対応がわかりやすいようにします。

C#
private string _email;

public string Email
{
get
{
return _email;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("メールアドレスは必須です。");
}

_email = value;
}
}

命名規則をそろえると、コードの読みやすさが大きく向上します。

まとめ

C#のプロパティは、クラスの値を外部から安全に取得・変更するための仕組みです。

csharp propertyの基本は、getで値を取得し、setで値を代入することです。

C#
public string Name { get; set; }

このような自動実装プロパティは、C#で最もよく使われる書き方の1つです。

一方、入力チェックや加工が必要な場合は、バッキングフィールドを使った通常のプロパティを使います。

C#
private int age;

public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
throw new ArgumentException("年齢は0以上で入力してください。");
}

age = value;
}
}

フィールドは値を保存する場所、プロパティはその値へのアクセスを制御する窓口です。publicフィールドを直接公開するよりも、プロパティを使った方が、カプセル化やデータ保護の面で安全です。

また、外部から変更されたくない値には、getのみ、private setinitなどを使うとよいでしょう。

C#
public int Id { get; }
public string Name { get; private set; }
public string Email { get; init; }

C#プロパティを使うときの基本方針は、次のように考えるとわかりやすいです。

単純に値を持つだけなら、自動実装プロパティを使います。

C#
public string Name { get; set; }

入力チェックが必要なら、通常のプロパティを使います。

C#
private string name;

public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は必須です。");
}

name = value;
}
}

外部から変更されたくない値は、private setgetのみを使います。

C#
public DateTime CreatedAt { get; }
public string Status { get; private set; }

プロパティは、C#のクラス設計に欠かせない基本機能です。最初は{ get; set; }の形から覚え、慣れてきたらバッキングフィールド、バリデーション、読み取り専用プロパティ、private setinitなどを使い分けていきましょう。