C#のget/setとは?プロパティの基本と使い方を初心者向けにわかりやすく解説

はじめに

C#を学び始めると、クラスの中でよく見かけるのがgetsetです。

C#
public string Name { get; set; }

このような書き方を見て、「これは変数なの?」「getとsetは何をしているの?」「なぜわざわざ書く必要があるの?」と疑問に思う初心者は多いです。

C#のget/setは、プロパティという仕組みで使われます。プロパティを使うと、クラスが持つデータを外部から読み取ったり、変更したりできます。さらに、値を変更するときにチェックを入れたり、外部から勝手に変更されないように制限したりすることもできます。

この記事では、C#のget/setとは何か、プロパティとの関係、基本的な書き方、自動実装プロパティ、アクセス修飾子、初心者がつまずきやすいポイントまで、サンプルコードを使ってわかりやすく解説します。

1. C#のget/setとは?まず押さえたい基本

1-1. get/setはプロパティで値を読み書きするための仕組み

C#のgetsetは、プロパティの値を読み取る、または書き込むための仕組みです。

たとえば、次のようなコードがあります。

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

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

外部からは、次のように使えます。

C#
Person person = new Person();

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

このとき、person.Name = "Taro";setが使われ、Console.WriteLine(person.Name);getが使われます。

つまり、見た目は普通の変数のように扱えますが、内部ではgetsetによって値の取得や設定が行われています。

1-2. getは値の取得、setは値の設定を担当する

getは値を取り出すときに使われます。

C#
Console.WriteLine(person.Name);

このようにプロパティの値を読むと、getが呼び出されます。

一方、setは値を代入するときに使われます。

C#
person.Name = "Hanako";

このようにプロパティへ値を設定すると、setが呼び出されます。

通常のプロパティで書くと、次のようになります。

C#
public class Person
{
private string name;

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

getではreturnで値を返し、setではvalueを使って値を受け取ります。

1-3. get/setを使うとクラスのデータを安全に扱える

get/setを使う大きな理由は、クラスのデータを安全に扱うためです。

たとえば、年齢を表すAgeにマイナスの値が入るとおかしいです。

C#
person.Age = -10;

このような不正な値を防ぐために、setの中でチェックできます。

C#
public class Person
{
private int age;

public int Age
{
get
{
return age;
}
set
{
if (value < 0)
{
throw new ArgumentException("年齢にマイナスの値は設定できません。");
}

age = value;
}
}
}

このように、setを使うと「値を設定するときのルール」を作れます。

単に値を保存するだけでなく、クラスの状態を正しく保つためにもget/setは重要です。

1-4. 初心者が混同しやすい「変数」「フィールド」「プロパティ」の違い

C#のget/setを理解するには、「変数」「フィールド」「プロパティ」の違いを押さえる必要があります。

まず、変数はメソッドの中などで一時的に使う値です。

C#
int count = 10;

フィールドは、クラスの中に定義される変数のようなものです。オブジェクトが持つデータを保存します。

C#
public class Person
{
private string name;
}

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

一方、プロパティは、フィールドなどの値を外部から読み書きするための窓口です。

C#
public class Person
{
private string name;

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

初心者のうちは、次のように考えるとわかりやすいです。

  • フィールド:クラス内部で値を保存する場所

  • プロパティ:外部から値を読み書きするための入口

  • get:値を読む処理

  • set:値を書き込む処理

C#では、外部に公開するデータにはフィールドではなくプロパティを使うのが一般的です。

2. C#のプロパティとは?get/setとの関係

2-1. プロパティはクラスの外部に値を公開するためのメンバー

プロパティは、クラスが持つ値を外部から使えるようにするためのメンバーです。

たとえば、Personクラスに名前と年齢を持たせたい場合、次のように書けます。

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

使う側は、次のように値を設定したり取得したりできます。

C#
Person person = new Person();

person.Name = "Taro";
person.Age = 20;

Console.WriteLine(person.Name);
Console.WriteLine(person.Age);

プロパティは見た目としては変数のように使えますが、実際にはgetsetによって値の読み書きを制御できます。

2-2. フィールドを直接公開せずプロパティを使う理由

C#では、次のようにフィールドをpublicにすることもできます。

C#
public class Person
{
public string name;
}

この場合、外部から直接値を変更できます。

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

一見シンプルですが、フィールドを直接公開すると、値のチェックや制御が難しくなります。

たとえば、年齢にマイナスの値が入っても防げません。

C#
public class Person
{
public int age;
}
C#
person.age = -10;

これでは、オブジェクトが不正な状態になる可能性があります。

プロパティを使えば、外部からは同じように値を代入しているように見えても、内部でチェックを入れられます。

C#
public class Person
{
private int age;

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

age = value;
}
}
}

このように、プロパティは安全なデータ操作のために使われます。

2-3. カプセル化とget/setの関係

C#のget/setは、オブジェクト指向の重要な考え方であるカプセル化と深く関係しています。

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

たとえば、フィールドをprivateにして、プロパティを通して操作します。

C#
public class Product
{
private int price;

public int Price
{
get { return price; }
set
{
if (value < 0)
{
throw new ArgumentException("価格は0以上である必要があります。");
}

price = value;
}
}
}

この例では、priceフィールドは外部から直接変更できません。外部からはPriceプロパティを通して値を扱います。

これにより、クラスの内部状態を安全に守れます。

2-4. プロパティを使うメリット

C#でプロパティを使う主なメリットは、次の通りです。

プロパティを使うと、外部からはシンプルに値を読み書きできます。

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

一方で、クラス内部では値のチェックや加工ができます。

C#
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は空にできません。");
}

name = value;
}

また、外部から読み取りだけ許可して、変更はクラス内部だけに限定することもできます。

C#
public int Id { get; private set; }

このように、プロパティは「使いやすさ」と「安全性」を両立するための仕組みです。

3. C#のget/setの基本的な書き方

3-1. get/setを使ったプロパティの基本構文

C#のプロパティは、基本的に次のように書きます。

C#
アクセス修飾子  プロパティ名
{
get
{
return ;
}
set
{
= value;
}
}

具体例は次の通りです。

C#
public class Person
{
private string name;

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

この例では、nameというフィールドをNameプロパティで外部に公開しています。

C#では、プロパティ名は先頭を大文字にするのが一般的です。フィールド名は小文字または_nameのように書くことが多いです。

C#
private string _name;

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

3-2. getで値を返す書き方

getは、プロパティの値を取得するときに呼ばれます。

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

getの中では、returnを使って値を返します。

C#
Console.WriteLine(person.Name);

このように書くと、Nameプロパティのgetが実行され、nameフィールドの値が返されます。

getでは単にフィールドを返すだけでなく、値を加工して返すこともできます。

C#
public string DisplayName
{
get
{
return "名前:" + name;
}
}

この場合、内部のnameはそのままでも、外部には加工された文字列を返せます。

3-3. setで値を代入する書き方

setは、プロパティに値を設定するときに呼ばれます。

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

次のように代入すると、setが実行されます。

C#
person.Name = "Taro";

setの中では、代入された値をvalueキーワードで受け取ります。

たとえば、名前が空文字でないかをチェックすることもできます。

C#
public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は空にできません。");
}

name = value;
}
}

このように、setは単なる代入だけでなく、値の検証にもよく使われます。

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

valueは、setに渡される値を表す特別なキーワードです。

C#
person.Name = "Taro";

このコードの場合、setの中のvalueには"Taro"が入ります。

C#
set
{
name = value;
}

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

C#
name = "Taro";

valueは自分で宣言する必要はありません。C#がsetの中で自動的に使えるようにしてくれます。

型はプロパティの型と同じです。

C#
public int Age
{
set
{
age = value;
}
}

この場合、valueint型です。

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

この場合、valuestring型です。

初心者はvalueを通常の変数のように考えてしまいがちですが、set専用の特別な名前だと覚えておきましょう。

3-5. 実際に値を取得・設定するサンプルコード

実際にget/setを使ったサンプルを見てみましょう。

C#
using System;

public class Person
{
private string name;
private int age;

public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は空にできません。");
}

name = value;
}
}

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

age = value;
}
}
}

public class Program
{
public static void Main()
{
Person person = new Person();

person.Name = "Taro";
person.Age = 20;

Console.WriteLine(person.Name);
Console.WriteLine(person.Age);
}
}

実行結果は次のようになります。

Taro
20

person.Name = "Taro";Nameプロパティのsetが呼ばれます。

Console.WriteLine(person.Name);Nameプロパティのgetが呼ばれます。

このように、プロパティは使う側から見るとシンプルですが、内部ではgetsetによって処理を制御できます。

4. 自動実装プロパティの使い方

4-1. 自動実装プロパティとは

自動実装プロパティとは、フィールドを自分で書かずにプロパティを簡単に定義できる書き方です。

C#
public string Name { get; set; }

このように書くと、C#が内部的に値を保存する場所を自動で用意してくれます。

通常のプロパティでは、次のようにフィールドを用意する必要があります。

C#
private string name;

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

しかし、自動実装プロパティなら1行で書けます。

C#
public string Name { get; set; }

値のチェックや加工が不要な場合は、自動実装プロパティを使うのが一般的です。

4-2. { get; set; }の意味

{ get; set; }は、「このプロパティは読み取りも書き込みもできる」という意味です。

C#
public string Name { get; set; }

この場合、外部から次のように値を設定できます。

C#
person.Name = "Taro";

また、値を取得することもできます。

C#
Console.WriteLine(person.Name);

get;は値の取得を許可します。

set;は値の設定を許可します。

つまり、{ get; set; }は「読み書き可能なプロパティ」を意味します。

4-3. 自動実装プロパティのサンプルコード

自動実装プロパティを使うと、クラスを簡潔に書けます。

C#
using System;

public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}

public class Program
{
public static void Main()
{
Person person = new Person();

person.Name = "Taro";
person.Age = 20;

Console.WriteLine($"{person.Name}は{person.Age}歳です。");
}
}

実行結果は次のようになります。

Taroは20歳です。

このように、単純に値を持つだけのクラスであれば、自動実装プロパティで十分です。

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

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

自動実装プロパティは簡単に書けます。

C#
public int Age { get; set; }

ただし、このままだとマイナスの値も設定できてしまいます。

C#
person.Age = -10;

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

C#
private int age;

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

age = value;
}
}

単純な値の保存だけなら自動実装プロパティ、値のチェックや加工が必要なら通常のプロパティを使うと考えるとわかりやすいです。

4-5. 初心者はまず自動実装プロパティから覚えるべき理由

C#初心者は、まず自動実装プロパティから覚えるのがおすすめです。

理由は、書き方がシンプルで、C#のクラスを作るときによく使うからです。

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

このようなコードは、実際の開発でも頻繁に登場します。

最初から複雑なget/set処理を覚えようとすると、フィールド、プロパティ、value、アクセス修飾子などが混ざって難しく感じるかもしれません。

まずは次の形を覚えましょう。

C#
public  プロパティ名 { get; set; }

その後、値チェックが必要になったタイミングで、通常のプロパティを学ぶと理解しやすくなります。

5. get/setのアクセス修飾子と使い分け

5-1. public get/setの意味

public get; set;は、外部から値の取得も設定もできるという意味です。

C#
public string Name { get; set; }

この場合、クラスの外から自由に読み書きできます。

C#
Person person = new Person();

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

publicget/setは便利ですが、どこからでも変更できるため、重要な値には注意が必要です。

たとえば、ユーザーIDや注文番号のように、作成後に勝手に変えられると困る値には、public setを使わないほうがよい場合があります。

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

private setを使うと、外部から値を読み取ることはできますが、外部から変更できなくなります。

C#
public class User
{
public int Id { get; private set; }

public User(int id)
{
Id = id;
}
}

この場合、外部からIdを読むことはできます。

C#
Console.WriteLine(user.Id);

しかし、外部から変更しようとするとエラーになります。

C#
user.Id = 10;

private setは、クラス内部からだけ値を変更できるようにしたいときに使います。

たとえば、ID、作成日時、状態管理などに使われます。

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

public Order()
{
Status = "New";
}

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

この例では、Statusは外部から直接変更できません。代わりにCompleteメソッドを通して状態を変更します。

5-3. getのみの読み取り専用プロパティ

getだけを書くと、読み取り専用プロパティになります。

C#
public string Name { get; }

このプロパティは、外部から値を取得できますが、通常は外部から代入できません。

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

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

使う側は次のように読み取れます。

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

しかし、後から変更することはできません。

C#
person.Name = "Hanako";

このような読み取り専用プロパティは、作成後に変えたくない値を表すときに便利です。

5-4. setのみの書き込み専用プロパティは使うべきか

C#では、setだけのプロパティも作れます。

C#
public string Password
{
set
{
password = value;
}
}

この場合、値を設定することはできますが、取得はできません。

C#
user.Password = "secret";

しかし、次のように読み取ることはできません。

C#
Console.WriteLine(user.Password);

書き込み専用プロパティは使える場面が限られます。初心者のうちは、あまり使わないと考えてよいです。

理由は、プロパティは「値のように扱えるメンバー」として使われることが多く、読み取れないプロパティは直感的ではないからです。

パスワードのような値でも、単純に書き込み専用プロパティを作るより、SetPasswordのようなメソッドにしたほうが意図が伝わりやすい場合があります。

C#
public void SetPassword(string password)
{
this.password = password;
}

書き込み専用プロパティは文法としては可能ですが、実務では慎重に使いましょう。

5-5. public get; private set;の実用例

public get; private set;は、C#でよく使われるパターンです。

C#
public class BankAccount
{
public int Balance { get; private set; }

public void Deposit(int amount)
{
if (amount <= 0)
{
throw new ArgumentException("入金額は1以上である必要があります。");
}

Balance += amount;
}

public void Withdraw(int amount)
{
if (amount <= 0)
{
throw new ArgumentException("出金額は1以上である必要があります。");
}

if (amount > Balance)
{
throw new InvalidOperationException("残高が不足しています。");
}

Balance -= amount;
}
}

この例では、Balanceは外部から読み取れます。

C#
Console.WriteLine(account.Balance);

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

C#
account.Balance = 1000000;

残高はDepositWithdrawメソッドを通してのみ変更できます。

このように、public get; private set;を使うと、外部には情報を公開しつつ、不正な変更を防げます。

6. get/setを使った値チェックと制御

6-1. set内で不正な値を防ぐ方法

setの中では、代入される値をチェックできます。

たとえば、名前が空の場合にエラーにするには、次のように書きます。

C#
private string name;

public string Name
{
get
{
return name;
}
set
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException("名前は空にできません。");
}

name = value;
}
}

このようにすると、次のコードはエラーになります。

C#
person.Name = "";

set内でチェックすることで、クラスのデータを常に正しい状態に保ちやすくなります。

6-2. 年齢や価格などの入力チェック例

年齢や価格のように、マイナス値が不正なデータでは、setでチェックを入れると便利です。

C#
public class Product
{
private int price;

public int Price
{
get
{
return price;
}
set
{
if (value < 0)
{
throw new ArgumentException("価格は0以上である必要があります。");
}

price = value;
}
}
}

使い方は次の通りです。

C#
Product product = new Product();

product.Price = 1000;
Console.WriteLine(product.Price);

不正な値を設定すると、例外を発生させられます。

C#
product.Price = -500;

年齢の場合も同じです。

C#
public class Person
{
private int age;

public int Age
{
get
{
return age;
}
set
{
if (value < 0 || value > 150)
{
throw new ArgumentException("年齢は0〜150の範囲で設定してください。");
}

age = value;
}
}
}

このように、setは入力チェックの場所としてよく使われます。

6-3. getで加工した値を返す方法

getでは、保存している値をそのまま返すだけでなく、加工して返すこともできます。

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

public string FullName
{
get
{
return LastName + " " + FirstName;
}
}
}

使い方は次の通りです。

C#
Person person = new Person();

person.LastName = "山田";
person.FirstName = "太郎";

Console.WriteLine(person.FullName);

実行結果は次のようになります。

山田 太郎

FullNameは値を保存しているわけではなく、FirstNameLastNameから計算して返しています。

このようなプロパティは、計算プロパティとも呼ばれます。

6-4. バッキングフィールドを使うケース

バッキングフィールドとは、プロパティの値を内部で保存するためのフィールドです。

C#
private int age;

public int Age
{
get
{
return age;
}
set
{
age = value;
}
}

この例では、ageがバッキングフィールドです。

自動実装プロパティでは、C#がバッキングフィールドを自動的に用意してくれます。

C#
public int Age { get; set; }

しかし、値のチェックや加工が必要な場合は、自分でバッキングフィールドを書く必要があります。

C#
private string name;

public string Name
{
get
{
return name;
}
set
{
name = value.Trim();
}
}

この例では、設定された文字列の前後の空白を取り除いてから保存しています。

6-5. 自動実装プロパティではできない処理

自動実装プロパティは便利ですが、getsetの中に処理を書けません。

C#
public int Age { get; set; }

この書き方では、値のチェックができません。

C#
person.Age = -10;

マイナス値を防ぎたい場合は、通常のプロパティにする必要があります。

C#
private int age;

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

age = value;
}
}

また、値を加工して保存したい場合も、自動実装プロパティだけでは不十分です。

C#
private string email;

public string Email
{
get
{
return email;
}
set
{
email = value.Trim().ToLower();
}
}

このように、単純な値の保存なら自動実装プロパティ、処理が必要なら通常のプロパティを使い分けましょう。

7. get/setのよくある使い方

7-1. クラスのデータを外部から扱う

get/setのもっとも基本的な使い方は、クラスのデータを外部から扱うことです。

C#
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
public int Price { get; set; }
}

使う側は次のように書けます。

C#
Book book = new Book();

book.Title = "C#入門";
book.Author = "山田太郎";
book.Price = 2000;

Console.WriteLine(book.Title);
Console.WriteLine(book.Author);
Console.WriteLine(book.Price);

このように、プロパティを使うとオブジェクトの情報をわかりやすく扱えます。

7-2. オブジェクト初期化子で値を設定する

C#では、オブジェクトを作るときにプロパティへまとめて値を設定できます。

C#
Person person = new Person
{
Name = "Taro",
Age = 20
};

これをオブジェクト初期化子といいます。

クラスは次のように定義します。

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

オブジェクト初期化子を使うと、次のようなコードを短く書けます。

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

特に、プロパティが多いクラスではオブジェクト初期化子がよく使われます。

7-3. DTOやモデルクラスで使う

get/setは、DTOやモデルクラスでよく使われます。

DTOとは、データを運ぶためのクラスです。たとえば、ユーザー情報を表すDTOは次のように書けます。

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

モデルクラスでも、データを表すためにプロパティを使います。

C#
public class ProductModel
{
public int Id { get; set; }
public string ProductName { get; set; }
public int Price { get; set; }
}

このように、C#ではデータを表すクラスに{ get; set; }がよく登場します。

7-4. UnityやASP.NETなどで使われるプロパティ例

C#は、UnityやASP.NETでも広く使われています。

Unityでは、ゲーム内のキャラクター情報をプロパティで表すことがあります。

C#
public class Player
{
public string Name { get; set; }
public int Hp { get; private set; }

public void Damage(int amount)
{
Hp -= amount;

if (Hp < 0)
{
Hp = 0;
}
}
}

この例では、Hpは外部から読み取れますが、変更はDamageメソッドを通して行います。

ASP.NETでは、フォームやAPIで受け取るデータをモデルクラスとして定義することが多いです。

C#
public class RegisterUserRequest
{
public string UserName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}

このように、get/setはC#のさまざまな開発分野で使われています。

7-5. 初心者向けの実践サンプル

簡単な会員クラスを作ってみましょう。

C#
using System;

public class Member
{
private int point;

public string Name { get; set; }

public int Point
{
get
{
return point;
}
set
{
if (value < 0)
{
throw new ArgumentException("ポイントは0以上である必要があります。");
}

point = value;
}
}

public void AddPoint(int amount)
{
if (amount <= 0)
{
throw new ArgumentException("追加するポイントは1以上である必要があります。");
}

Point += amount;
}
}

public class Program
{
public static void Main()
{
Member member = new Member
{
Name = "Taro",
Point = 100
};

member.AddPoint(50);

Console.WriteLine($"{member.Name}さんのポイントは{member.Point}です。");
}
}

実行結果は次のようになります。

Taroさんのポイントは150です。

このサンプルでは、Nameは単純な自動実装プロパティ、Pointは値チェックを行う通常のプロパティにしています。

このように、必要に応じてプロパティの書き方を使い分けます。

8. get/setで初心者がつまずきやすいポイント

8-1. フィールドとプロパティを同じものだと思ってしまう

初心者がよく混同するのが、フィールドとプロパティです。

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

nameはフィールド、Nameはプロパティです。

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

プロパティは、外部からデータを読み書きするための窓口です。

自動実装プロパティの場合は、フィールドが見えないため、変数と同じように感じるかもしれません。

C#
public string Name { get; set; }

しかし、これはフィールドではなくプロパティです。

外部に公開するデータは、基本的にプロパティとして定義すると覚えておきましょう。

8-2. valueキーワードの役割がわからない

valueは、setに渡された値を表すキーワードです。

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

たとえば、次のように代入した場合、

C#
person.Name = "Taro";

valueには"Taro"が入ります。

つまり、setの中では次のような処理が行われているイメージです。

C#
name = "Taro";

valueは自分で作った変数ではありません。setの中で自動的に使える特別なキーワードです。

8-3. private setの意味を誤解する

private setは、「値を変更できない」という意味ではありません。

C#
public int Id { get; private set; }

これは、外部からは変更できないが、クラス内部からは変更できるという意味です。

C#
public class User
{
public int Id { get; private set; }

public void ChangeId(int id)
{
Id = id;
}
}

このように、クラスの中ではIdを変更できます。

外部からは変更できません。

C#
user.Id = 10;

private setは、値の変更を完全に禁止するものではなく、変更できる場所をクラス内部に制限するものです。

8-4. get/setを書けば何でも安全になると思ってしまう

get/setを書いたからといって、自動的に安全になるわけではありません。

次のプロパティは、get/setを使っていますが、値のチェックはしていません。

C#
public int Age { get; set; }

この場合、マイナスの年齢も設定できてしまいます。

C#
person.Age = -10;

値を安全に扱いたい場合は、setの中にチェック処理を書く必要があります。

C#
private int age;

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

age = value;
}
}

get/setは安全性を高めるための仕組みですが、実際に安全にするには適切な処理を書く必要があります。

8-5. 無限ループになる間違った書き方

初心者が特に注意したいのが、プロパティの中で同じプロパティを使ってしまうミスです。

次のコードは間違いです。

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

getの中でNameを返すと、またgetが呼ばれます。すると、さらにgetが呼ばれ続け、無限ループのような状態になります。

setの中でName = value;と書くのも同じです。setが自分自身を呼び続けてしまいます。

正しくは、バッキングフィールドを使います。

C#
private string name;

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

プロパティの中では、プロパティ自身ではなく、フィールドを使うと覚えておきましょう。

9. get/setと関連して覚えたいC#の機能

9-1. initアクセサとは

initアクセサは、オブジェクトの初期化時だけ値を設定できる仕組みです。

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

このプロパティは、オブジェクト初期化子で設定できます。

C#
Person person = new Person
{
Name = "Taro"
};

しかし、作成後に変更しようとするとエラーになります。

C#
person.Name = "Hanako";

initは、作成時にだけ値を設定し、その後は変更されたくないデータに使います。

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

setは後からでも値を変更できますが、initは初期化時だけ設定できます。

9-2. readonlyとの違い

readonlyは、フィールドに対して使うキーワードです。

C#
public class Person
{
private readonly string name;

public Person(string name)
{
this.name = name;
}
}

readonlyフィールドは、宣言時またはコンストラクタ内でのみ値を設定できます。

一方、プロパティでは次のように読み取り専用にできます。

C#
public string Name { get; }

このプロパティは、コンストラクタで値を設定できます。

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

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

簡単にいうと、readonlyはフィールドに使うもの、getのみのプロパティは外部に読み取り専用で公開するためのものです。

9-3. コンストラクタで値を設定する方法

読み取り専用プロパティは、コンストラクタで値を設定することが多いです。

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

public Person(string name, int age)
{
Name = name;
Age = age;
}
}

使う側は次のように書きます。

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

Console.WriteLine(person.Name);
Console.WriteLine(person.Age);

作成後に変更できないため、データの一貫性を保ちやすくなります。

C#
person.Age = 30;

このような代入はできません。

作成時に必要な値はコンストラクタで受け取り、作成後に変えたくない値はgetのみのプロパティにするのがよくある設計です。

9-4. ラムダ式を使った読み取り専用プロパティ

C#では、短いget処理をラムダ式のような形で書けます。これを式形式のプロパティといいます。

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

public string FullName => LastName + " " + FirstName;
}

これは、次の書き方と似ています。

C#
public string FullName
{
get
{
return LastName + " " + FirstName;
}
}

短い計算プロパティであれば、式形式を使うとコードをすっきり書けます。

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

ただし、初心者のうちは通常のgetの書き方を理解してから使うとよいでしょう。

9-5. レコード型とプロパティの関係

C#には、データを表すために便利なレコード型があります。

C#
public record Person(string Name, int Age);

このように書くと、NameAgeのようなプロパティを持つ型を簡潔に定義できます。

通常のクラスで書くと、次のようなイメージです。

C#
public class Person
{
public string Name { get; init; }
public int Age { get; init; }
}

レコード型は、変更されにくいデータを扱うときに便利です。

C#
Person person = new Person("Taro", 20);
Console.WriteLine(person.Name);

レコード型でも、プロパティの考え方は重要です。

C#でDTO、設定値、APIのレスポンスなどを扱うときには、レコード型とプロパティを組み合わせて使う場面があります。

10. C#のget/setに関するよくある質問

10-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; }

目的に応じて、getsetを使い分けます。

10-2. publicフィールドではなくプロパティを使うべき?

基本的には、publicフィールドではなくプロパティを使うべきです。

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;
}
}

外部に公開する値は、プロパティで表すのがC#では一般的です。

10-3. getだけ、setだけでも使える?

はい、使えます。

getだけのプロパティは読み取り専用です。

C#
public string Name { get; }

setだけのプロパティは書き込み専用です。

C#
public string Password
{
set
{
password = value;
}
}

ただし、setだけのプロパティは使いどころが少なく、初心者にはあまりおすすめしません。

値を設定するだけで読み取らせたくない場合は、メソッドにしたほうが意図がわかりやすいこともあります。

C#
public void SetPassword(string password)
{
this.password = password;
}

10-4. 自動実装プロパティと通常のプロパティはどちらを使うべき?

単純に値を保存するだけなら、自動実装プロパティを使うのがおすすめです。

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

値のチェックや加工が必要な場合は、通常のプロパティを使います。

C#
private int age;

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

age = value;
}
}

初心者は、まず自動実装プロパティを覚え、その後に通常のプロパティを使えるようになるとよいです。

10-5. get/setはメソッドと何が違う?

get/setは、内部的にはメソッドに近い仕組みですが、使う側からは値のように扱えます。

プロパティは次のように使います。

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

メソッドなら次のような形になります。

C#
person.SetName("Taro");
Console.WriteLine(person.GetName());

プロパティは、名前や年齢のような「データ」を表すときに向いています。

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

一方、何かの処理や動作を表す場合はメソッドにするのが自然です。

C#
public void Save()
{
// 保存処理
}

値を表すならプロパティ、動作を表すならメソッド、と考えるとわかりやすいです。

まとめ

C#のget/setは、プロパティで値を読み書きするための仕組みです。

getは値を取得するときに使われ、setは値を設定するときに使われます。

C#
public string Name { get; set; }

このような自動実装プロパティは、C#で非常によく使われる基本的な書き方です。

単純に値を持たせたい場合は、自動実装プロパティを使うと簡潔に書けます。

C#
public int Age { get; set; }

一方、値のチェックや加工が必要な場合は、通常のプロパティを使います。

C#
private int age;

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

age = value;
}
}

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

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

C#のget/setを理解すると、クラスの設計、カプセル化、データの安全な扱い方がわかりやすくなります。

初心者はまず、次の3つを押さえましょう。

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

public int Age
{
get { return age; }
set { age = value; }
}

この3つを理解できれば、C#のプロパティの基本は十分に身につきます。C#でクラスを作るときは、フィールドを直接公開するのではなく、プロパティとget/setを使って、安全でわかりやすいコードを書くことを意識しましょう。