C#プロパティとは?get/setの使い方と自動実装を初心者向けにわかりやすく解説
はじめに
C#でクラスを作成するとき、データを扱うためによく利用されるのが「プロパティ」です。
プロパティを使うと、クラスが持つ値を外部から簡単に取得・設定できます。また、値を設定するときに入力内容をチェックしたり、外部からの変更を禁止したりすることも可能です。
プロパティは、C#のオブジェクト指向プログラミングを理解するうえで欠かせない仕組みです。しかし、初心者のうちは「フィールドと何が違うのか」「getやsetは何をしているのか」と疑問に感じることもあるでしょう。
この記事では、C#プロパティの基本から、get/set、自動実装プロパティ、アクセス修飾子、実践的な使い方まで、コード例を交えながらわかりやすく解説します。
1. C#のプロパティとは?まず押さえたい基本
1-1. プロパティはクラスの値を安全に扱うための仕組み
C#のプロパティとは、クラスが持つ値を外部から取得したり、設定したりするための仕組みです。
次のコードでは、PersonクラスにNameプロパティを定義しています。
public class Person{public string Name { get; set; } = "";}このプロパティは、次のように通常の変数と似た書き方で利用できます。
Person person = new Person();person.Name = "田中";Console.WriteLine(person.Name);
実行結果は次のとおりです。
田中person.Name = "田中";で値を設定し、person.Nameで値を取得しています。
プロパティは変数のように見えますが、内部的には値を取得する処理と設定する処理を持っています。そのため、単純にデータを公開するだけでなく、必要に応じて処理を追加できる点が特徴です。
1-2. フィールドとプロパティの違い
フィールドとは、クラスの内部に値を保存するための変数です。
public class Person{private string name = "";}一方、プロパティは、その値を取得・設定するための窓口として利用されます。
public class Person{private string name = "";public string Name{get{return name;}set{name = value;}}
}
フィールドとプロパティの主な違いは、値を読み書きするときに処理を追加できるかどうかです。
フィールドを直接公開すると、外部から自由に値を変更されてしまいます。
public class Person{public int Age;}この場合、次のような不正な値も設定できます。
Person person = new Person();person.Age = -100;プロパティを使えば、値を設定する前にチェックできます。
public class Person{private int age;public int Age{get{return age;}set{if (value >= 0){age = value;}}}
}
このように、フィールドには実際の値を保存し、プロパティには外部とのデータの受け渡しを担当させるのが基本的な考え方です。
1-3. メソッドではなくプロパティを使う場面
値を取得するだけであれば、メソッドを使うこともできます。
public string GetName(){return name;}値を設定するメソッドも作成できます。
public void SetName(string newName){name = newName;}しかし、名前や年齢、価格など、オブジェクトの状態を表すデータにはプロパティを使うのが一般的です。
person.Name = "佐藤";Console.WriteLine(person.Name);プロパティを使うと、通常の変数に近い自然な書き方ができます。
一方、データを取得するだけでなく、時間のかかる処理や外部通信、副作用を伴う操作を実行する場合は、メソッドのほうが適しています。
たとえば、次のような処理です。
order.CalculateTotal();order.Save();order.SendConfirmationEmail();単純な状態の取得・設定にはプロパティを使い、明確な動作や処理を表す場合にはメソッドを使うと考えるとよいでしょう。
1-4. 初心者がプロパティを学ぶべき理由
プロパティは、C#の多くの場面で利用されています。
たとえば、次のような開発ではプロパティの理解が欠かせません。
クラスを使ったオブジェクト指向プログラミング
ASP.NET CoreによるWebアプリ開発
データベースと連携するアプリの開発
Windowsアプリやゲームの開発
JSONデータの読み込みや書き出し
また、プロパティを学ぶことで、クラスの内部状態を外部から守る「カプセル化」についても理解しやすくなります。
C#で本格的なプログラムを作成するためには、プロパティの基本構文だけでなく、どの値を公開し、どの値を変更できないようにするかという設計の考え方も重要です。
2. C#プロパティの基本構文
2-1. getとsetを使ったプロパティの書き方
getとsetを使ったプロパティの基本構文は次のとおりです。
アクセス修飾子 データ型 プロパティ名{get{return フィールド;}set{フィールド = value;}}実際のコードにすると、次のようになります。
public class Product{private int price;public int Price{get{return price;}set{price = value;}}
}
それぞれの要素には、次のような役割があります。
public:外部からアクセスできることを表すint:プロパティが扱うデータ型Price:プロパティ名get:値を取得するときに実行されるset:値を設定するときに実行されるvalue:プロパティに設定しようとしている値
2-2. getアクセサとは?値を取得する仕組み
getアクセサは、プロパティの値が読み取られたときに実行されます。
public int Price{get{return price;}}次のコードでproduct.Priceを参照すると、getアクセサが呼び出されます。
Product product = new Product();int currentPrice = product.Price;getアクセサでは、プロパティの型と互換性のある値を返す必要があります。
たとえば、Priceがint型であれば、getアクセサもint型の値を返します。
public int Price{get{return 1000;}}このように、getアクセサは必ずしもフィールドの値をそのまま返す必要はありません。計算結果や加工した値を返すこともできます。
2-3. setアクセサとは?値を設定する仕組み
setアクセサは、プロパティに値が代入されたときに実行されます。
public int Price{set{price = value;}}次のコードを実行すると、setアクセサが呼び出されます。
Product product = new Product();product.Price = 1500;このとき、1500がsetアクセサ内のvalueに渡されます。
setアクセサでは、値をフィールドに保存するだけでなく、入力値の確認や変換も行えます。
public int Price{get{return price;}set{if (value < 0){price = 0;}else{price = value;}}}この例では、負の値が設定された場合に、価格を0にしています。
2-4. valueキーワードの意味と使い方
valueは、setアクセサの中で利用できる特別なキーワードです。プロパティに代入された値を表します。
product.Price = 2000;このコードが実行された場合、setアクセサ内のvalueは2000になります。
public int Price{get{return price;}set{price = value;}}valueの型は、プロパティの型と同じです。
Priceがint型ならvalueもint型になり、Nameがstring型ならvalueもstring型になります。
private string name = "";public string Name{get{return name;}set{name = value;}}
valueは自分で宣言する変数ではありません。setアクセサが呼び出されたときに、C#が自動的に用意します。
2-5. プロパティを呼び出す基本コード例
次の例では、クラスにプロパティを定義し、外部から値を設定・取得しています。
public class Student{private string name = "";private int score;public string Name{get{return name;}set{name = value;}}public int Score{get{return score;}set{score = value;}}
}
プロパティは次のように呼び出します。
Student student = new Student();student.Name = "山田";student.Score = 85;
Console.WriteLine(student.Name);Console.WriteLine(student.Score);
実行結果は次のとおりです。
山田85値を代入するとsetアクセサが実行され、値を参照するとgetアクセサが実行されます。
3. get/setの使い方をコードでわかりやすく解説
3-1. 読み書きできるプロパティの例
getとsetの両方を定義したプロパティは、値の読み取りと書き込みができます。
public class User{private string userName = "";public string UserName{get{return userName;}set{userName = value;}}
}
利用例は次のとおりです。
User user = new User();user.UserName = "CSharpUser";Console.WriteLine(user.UserName);
user.UserName = "CSharpUser";ではsetが実行され、Console.WriteLine(user.UserName);ではgetが実行されます。
getとsetの両方が必要で、特別な処理も行わない場合は、後述する自動実装プロパティを使うと簡潔に書けます。
3-2. 読み取り専用プロパティの例
getだけを定義し、setを定義しないプロパティは、外部から値を変更できない読み取り専用プロパティになります。
public class Circle{private double radius = 5.0;public double Radius{get{return radius;}}
}
値を取得することはできます。
Circle circle = new Circle();Console.WriteLine(circle.Radius);しかし、外部から値を代入するとコンパイルエラーになります。
circle.Radius = 10.0;読み取り専用プロパティは、計算結果を公開するときにも便利です。
public class Rectangle{public double Width { get; set; }public double Height { get; set; }public double Area{get{return Width * Height;}}
}
次のように面積を取得できます。
Rectangle rectangle = new Rectangle();rectangle.Width = 5;rectangle.Height = 3;
Console.WriteLine(rectangle.Area);
AreaはWidthとHeightから計算されるため、外部から直接変更させる必要がありません。
3-3. 書き込み専用プロパティは使うべきか
setだけを定義し、getを持たない書き込み専用プロパティも作成できます。
public class Account{private string password = "";public string Password{set{password = value;}}
}
値を設定することはできます。
Account account = new Account();account.Password = "sample-password";一方、値を読み取ることはできません。
Console.WriteLine(account.Password);ただし、書き込み専用プロパティは、値を参照できないため直感的に扱いにくく、利用される場面は多くありません。
パスワードの変更など、設定だけを行わせたい場合でも、次のようなメソッドにしたほうが処理の目的が明確になることがあります。
public void ChangePassword(string newPassword){password = newPassword;}特別な理由がない限り、setだけのプロパティを作るよりも、目的がわかる名前のメソッドを検討するとよいでしょう。
3-4. set内で入力値をチェックする方法
setアクセサでは、値をフィールドに保存する前に入力内容を確認できます。
public class Person{private int age;public int Age{get{return age;}set{if (value < 0){throw new ArgumentOutOfRangeException(nameof(value),"年齢には0以上の値を指定してください。");}age = value;}}
}
次のコードでは、正常な値を設定できます。
Person person = new Person();person.Age = 20;一方、負の値を設定すると例外が発生します。
person.Age = -1;文字列が空でないかを確認することもできます。
public class Product{private string name = "";public string Name{get{return name;}set{if (string.IsNullOrWhiteSpace(value)){throw new ArgumentException("商品名を入力してください。",nameof(value));}name = value;}}
}
このように、プロパティを通して値を設定させれば、クラス内に不正な値が保存されるのを防ぎやすくなります。
3-5. プロパティでカプセル化を実現する方法
カプセル化とは、クラス内部のデータや処理を外部から隠し、必要な部分だけを公開する考え方です。
プロパティを使う場合、フィールドをprivateにして外部から直接操作できないようにします。そのうえで、必要な操作だけをpublicプロパティとして公開します。
public class BankAccount{private decimal balance;public decimal Balance{get{return balance;}}public void Deposit(decimal amount){if (amount <= 0){throw new ArgumentOutOfRangeException(nameof(amount),"入金額は0より大きい値にしてください。");}balance += amount;}
}
利用側では残高を確認できます。
BankAccount account = new BankAccount();account.Deposit(5000);Console.WriteLine(account.Balance);
しかし、残高を直接書き換えることはできません。
account.Balance = -10000;残高の変更方法をDepositメソッドなどに限定することで、不正な操作を防げます。これがプロパティを活用したカプセル化の一例です。
4. 自動実装プロパティとは?
4-1. 自動実装プロパティの基本構文
自動実装プロパティとは、値を保存するフィールドを自分で記述せず、簡潔に定義できるプロパティです。
基本構文は次のとおりです。
public データ型 プロパティ名 { get; set; }たとえば、名前を表すプロパティは次のように書けます。
public string Name { get; set; } = "";クラス全体では次のようになります。
public class Person{public string Name { get; set; } = "";public int Age { get; set; }}値の設定と取得は、通常のプロパティと同じです。
Person person = new Person();person.Name = "鈴木";person.Age = 30;
Console.WriteLine(person.Name);Console.WriteLine(person.Age);
自動実装プロパティでは、値を保存するための領域がコンパイラによって自動的に用意されます。
4-2. 通常のプロパティとの違い
通常のプロパティでは、自分でフィールドを宣言します。
private string name = "";public string Name{get{return name;}set{name = value;}}
自動実装プロパティでは、同じような機能を次の1行で記述できます。
public string Name { get; set; } = "";どちらも利用側の書き方は同じです。
person.Name = "高橋";Console.WriteLine(person.Name);大きな違いは、getやsetの中に独自の処理を書けるかどうかです。
通常のプロパティであれば、値のチェックや加工を行えます。
private string name = "";public string Name{get{return name;}set{name = value.Trim();}}
自動実装プロパティの単純なget; set;には、このような処理を直接追加できません。
4-3. 自動実装プロパティを使うメリット
自動実装プロパティの主なメリットは、コードを短く、読みやすくできることです。
通常のプロパティでは、フィールド、get、setをそれぞれ記述する必要があります。
private int age;public int Age{get{return age;}set{age = value;}}
自動実装プロパティなら、次の1行で済みます。
public int Age { get; set; }記述量が減るため、プロパティの数が多いクラスでもコードを把握しやすくなります。また、フィールド名の書き間違いなども減らせます。
getやsetで特別な処理を必要としない場合は、自動実装プロパティを利用するのが一般的です。
4-4. 自動実装プロパティが向いているケース
自動実装プロパティは、値をそのまま保存・取得するだけのケースに向いています。
たとえば、商品データを表すクラスは次のように書けます。
public class Product{public int Id { get; set; }public string Name { get; set; } = "";public decimal Price { get; set; }}この例では、それぞれの値を設定するときに特別な処理を行っていません。そのため、自動実装プロパティが適しています。
一方、次のような処理が必要な場合は、通常のプロパティを検討します。
値の範囲をチェックする
文字列の前後にある空白を削除する
値を設定したときに別の処理を実行する
値を取得するときに加工する
独自のフィールドと連携する
最初は自動実装プロパティを使い、独自処理が必要になった段階で通常のプロパティへ変更する方法もあります。
4-5. 初期値を設定する方法
自動実装プロパティには、宣言と同時に初期値を設定できます。
public class User{public string Name { get; set; } = "ゲスト";public int Level { get; set; } = 1;public bool IsActive { get; set; } = true;}オブジェクトを作成した直後から、指定した初期値が設定されています。
User user = new User();Console.WriteLine(user.Name);Console.WriteLine(user.Level);Console.WriteLine(user.IsActive);
実行結果は次のとおりです。
ゲスト1True参照型のプロパティでは、必要に応じて初期値を明示しておくと扱いやすくなります。
public string Name { get; set; } = "";public List<string> Tags { get; set; } = new List<string>();コレクションを初期化しておけば、オブジェクト作成後すぐに要素を追加できます。
Product product = new Product();product.Tags.Add("新商品");5. アクセス修飾子とプロパティの使い分け
5-1. publicプロパティの使い方
publicを指定したプロパティは、クラスの外部からアクセスできます。
public class Employee{public string Name { get; set; } = "";}利用側では、次のように値を設定・取得できます。
Employee employee = new Employee();employee.Name = "佐々木";Console.WriteLine(employee.Name);
外部から利用してもらう必要がある情報は、publicプロパティとして公開します。
ただし、すべてのプロパティを無条件にpublicにすると、クラスの状態を自由に変更される可能性があります。値を外部から変更させる必要があるかどうかを考えて設計することが大切です。
5-2. privateフィールドとpublicプロパティの組み合わせ
C#では、privateフィールドとpublicプロパティを組み合わせることがあります。
public class Product{private decimal price;public decimal Price{get{return price;}set{if (value < 0){throw new ArgumentOutOfRangeException(nameof(value),"価格には0以上の値を指定してください。");}price = value;}}
}
priceフィールドはprivateなので、クラスの外部から直接変更できません。
Product product = new Product();product.Price = 1000;外部から値を変更するときは、必ずPriceプロパティのsetを通ります。これにより、値のチェックを確実に実行できます。
5-3. private setで外部からの変更を防ぐ方法
getは外部に公開し、setだけをクラス内部に限定することもできます。
public class Player{public int Score { get; private set; }public void AddScore(int points){if (points < 0){throw new ArgumentOutOfRangeException(nameof(points));}Score += points;}
}
Scoreの値は外部から取得できます。
Player player = new Player();Console.WriteLine(player.Score);しかし、外部から直接変更することはできません。
player.Score = 100;値を変更するには、クラスが用意したメソッドを使用します。
player.AddScore(100);Console.WriteLine(player.Score);private setは、次のような値に適しています。
注文の状態
ゲームのスコア
アカウントの残高
作成日時
処理回数
外部には値を見せたいものの、変更方法はクラス側で管理したい場合に便利です。
5-4. protectedやinternalを使う場面
プロパティには、publicやprivate以外のアクセス修飾子も指定できます。
protectedを指定すると、そのクラス自身と継承先のクラスからアクセスできます。
public class Character{protected int Health { get; set; } = 100;}public class Warrior : Character{public void TakeDamage(int damage){Health -= damage;}}
Healthは通常の外部コードからアクセスできませんが、継承したWarriorクラスからはアクセスできます。
internalを指定すると、同じアセンブリ内からアクセスできます。
internal string ManagementCode { get; set; } = "";internalは、同じプロジェクトやライブラリ内では利用したいものの、ライブラリの利用者には公開したくない場合などに使われます。
また、プロパティ本体とアクセサでアクセス範囲を変えることもできます。
public string Status { get; protected set; } = "未処理";この例では、値の取得はどこからでも可能ですが、設定できるのはクラス自身と継承先のクラスだけです。
5-5. 安全なプロパティ設計の考え方
安全なプロパティを設計するためには、外部に必要以上の変更権限を与えないことが重要です。
たとえば、次のプロパティは外部から自由に残高を変更できます。
public decimal Balance { get; set; }これでは、次のような変更も可能です。
account.Balance = -1000000;残高が入金や出金によってのみ変化するべきなら、setを非公開にします。
public decimal Balance { get; private set; }public void Deposit(decimal amount){if (amount <= 0){throw new ArgumentOutOfRangeException(nameof(amount));}
Balance += amount;
}
プロパティを設計するときは、次の点を考えましょう。
外部から値を取得する必要があるか
外部から自由に変更してよいか
値の設定時に検証が必要か
値の変更方法をメソッドに限定すべきか
クラス内部だけで利用する情報ではないか
最初からすべてを公開するのではなく、必要な範囲だけを公開するのが安全な設計につながります。
6. C#プロパティの実践的な使い方
6-1. クラスでプロパティを定義する例
商品情報を表すクラスにプロパティを定義してみましょう。
public class Product{public int Id { get; set; }public string Name { get; set; } = "";public decimal Price { get; set; }public int Stock { get; private set; }public void AddStock(int quantity){if (quantity <= 0){throw new ArgumentOutOfRangeException(nameof(quantity));}Stock += quantity;}
}
利用例は次のとおりです。
Product product = new Product();product.Id = 1;product.Name = "キーボード";product.Price = 5000;product.AddStock(10);
Console.WriteLine(product.Name);Console.WriteLine(product.Price);Console.WriteLine(product.Stock);
Id、Name、Priceは外部から設定できます。一方、Stockはprivate setなので、AddStockメソッドを通してのみ変更できます。
このように、値の性質に応じてプロパティの公開範囲を変えることが重要です。
6-2. オブジェクト初期化子でプロパティに値を入れる方法
オブジェクト初期化子を使うと、オブジェクトの作成とプロパティへの代入をまとめて記述できます。
Product product = new Product{Id = 1,Name = "マウス",Price = 3000};通常の書き方では、次のように1つずつ代入します。
Product product = new Product();product.Id = 1;product.Name = "マウス";product.Price = 3000;
どちらも結果は同じですが、オブジェクト初期化子を使うと、初期設定の内容をひとまとまりにして読みやすくできます。
複数のオブジェクトを作成するときにも便利です。
List<Product> products = new List<Product>{new Product{Id = 1,Name = "マウス",Price = 3000},new Product{Id = 2,Name = "キーボード",Price = 5000}};オブジェクト初期化子で指定できるのは、利用する場所からアクセス可能なsetまたはinitを持つプロパティです。private setのプロパティには、クラスの外部から値を設定できません。
6-3. コンストラクタとプロパティの使い分け
コンストラクタは、オブジェクトを作成するときに実行される特別な処理です。
必ず必要な値はコンストラクタで受け取り、任意の値はプロパティで設定する方法があります。
public class User{public int Id { get; }public string Name { get; set; }public string Email { get; set; } = "";public User(int id, string name){Id = id;Name = name;}
}
利用例は次のとおりです。
User user = new User(1, "田中"){Email = "tanaka@example.com"};この例では、IdとNameはユーザーを作成するために必要な値としてコンストラクタで受け取ります。Emailは後から設定できる任意の値です。
コンストラクタとプロパティは、次のように使い分けるとよいでしょう。
オブジェクトの作成に不可欠な値はコンストラクタで受け取る
後から変更できる値はプロパティにする
外部から変更させたくない値はgetだけ、またはprivate setにする
初期設定が任意の値はオブジェクト初期化子で設定する
すべての値をプロパティにすると、必要な値が未設定のままオブジェクトを利用できてしまうことがあります。クラスが常に正しい状態になるように設計することが大切です。
6-4. 計算結果を返すプロパティの作り方
プロパティは、保存されている値だけでなく、計算結果を返すためにも利用できます。
public class OrderItem{public decimal UnitPrice { get; set; }public int Quantity { get; set; }public decimal Subtotal{get{return UnitPrice * Quantity;}}
}
利用例は次のとおりです。
OrderItem item = new OrderItem{UnitPrice = 1200,Quantity = 3};Console.WriteLine(item.Subtotal);
実行結果は次のとおりです。
3600簡単な計算であれば、式形式のプロパティとして短く書くこともできます。
public decimal Subtotal => UnitPrice * Quantity;氏名を組み立てるプロパティも作成できます。
public class Person{public string LastName { get; set; } = "";public string FirstName { get; set; } = "";public string FullName => $"{LastName} {FirstName}";
}
計算元となる値が変われば、プロパティの取得結果も変わります。そのため、計算結果を別のフィールドに重複して保存せずに済みます。
ただし、非常に時間のかかる処理や外部通信をプロパティのgetで行うと、利用側が処理の重さを判断しにくくなります。そのような処理にはメソッドを使うほうが適切です。
6-5. staticプロパティの使い方
staticプロパティは、個別のオブジェクトではなく、クラス自体に属するプロパティです。
public class AppSettings{public static string ApplicationName { get; set; } = "SampleApp";}staticプロパティを利用するときは、オブジェクトを作成せず、クラス名からアクセスします。
Console.WriteLine(AppSettings.ApplicationName);AppSettings.ApplicationName = "NewApp";
オブジェクトごとに異なる値を持たせる通常のプロパティとは異なり、staticプロパティの値はクラス全体で共有されます。
オブジェクトの作成数を数える例は次のとおりです。
public class User{public static int CreatedCount { get; private set; }public string Name { get; set; }public User(string name){Name = name;CreatedCount++;}
}
利用例は次のとおりです。
User user1 = new User("田中");User user2 = new User("佐藤");Console.WriteLine(User.CreatedCount);
実行結果は次のとおりです。
2staticプロパティは共有設定や共通情報に便利ですが、どこからでも値が変更できる設計にすると、変更箇所を追いにくくなります。必要に応じてprivate setなどを使用しましょう。
7. 初心者がつまずきやすいプロパティの注意点
7-1. フィールドをpublicにしないほうがよい理由
フィールドをpublicにすると、外部から直接値を変更できます。
public class Person{public int Age;}この設計では、次のような不正な値も保存できます。
Person person = new Person();person.Age = -50;後から値のチェックを追加したくなった場合も、公開フィールドを利用しているすべてのコードへの影響を考える必要があります。
プロパティで公開しておけば、利用側の書き方を大きく変えずに、setへチェック処理を追加できます。
public class Person{private int age;public int Age{get{return age;}set{if (value < 0){throw new ArgumentOutOfRangeException(nameof(value));}age = value;}}
}
クラスの内部データはprivateフィールドで管理し、外部に必要な値はプロパティで公開するのが基本です。
7-2. get/setの中で無限ループが起きる原因
プロパティのgetやsetで、同じプロパティ自身を参照すると無限に呼び出されてしまいます。
次のコードは誤りです。
public string Name{get{return Name;}set{Name = value;}}Nameを取得すると、getの中で再びNameを取得しようとします。その結果、getが繰り返し呼び出されます。
setでも、Name = value;によって同じsetが再び呼び出されます。
通常のプロパティでは、別に用意したフィールドを参照します。
private string name = "";public string Name{get{return name;}set{name = value;}}
プロパティ名はName、フィールド名はnameです。大文字・小文字の違いを見落とさないように注意しましょう。
特別な処理が不要であれば、自動実装プロパティを使うことで、このようなミスを避けられます。
public string Name { get; set; } = "";7-3. プロパティ名とフィールド名の付け方
C#では、一般的にプロパティ名をパスカルケースで記述します。
public string UserName { get; set; } = "";public int ProductPrice { get; set; }パスカルケースとは、単語の先頭を大文字にする形式です。
一方、privateフィールドには、先頭にアンダースコアを付けたキャメルケースを使う書き方があります。
private string _userName = "";private int _productPrice;プロパティと組み合わせると次のようになります。
private string _userName = "";public string UserName{get{return _userName;}set{_userName = value;}}
アンダースコアを使わず、フィールド名の先頭を小文字にする書き方もあります。
private string userName = "";public string UserName { get; set; } = "";どちらの形式を採用する場合でも、プロジェクト内で命名規則を統一することが重要です。
7-4. 自動実装プロパティでできないこと
単純な自動実装プロパティでは、getやsetの処理内容を自由に記述できません。
public int Age { get; set; }年齢が0以上かどうかを確認したい場合は、通常のプロパティに変更します。
private int age;public int Age{get{return age;}set{if (value < 0){throw new ArgumentOutOfRangeException(nameof(value));}
age = value;}
}
また、入力された文字列を加工して保存する場合も通常のプロパティが必要です。
private string name = "";public string Name{get{return name;}set{name = value.Trim();}}
自動実装プロパティは便利ですが、すべてのケースに適しているわけではありません。
値をそのまま扱う場合は自動実装プロパティ、独自の処理が必要な場合は通常のプロパティと使い分けましょう。
7-5. プロパティと変数を混同しないためのポイント
プロパティは変数と似た書き方で利用できますが、同じものではありません。
ローカル変数は、メソッドの中で一時的に値を保存します。
public void ShowMessage(){string message = "こんにちは";Console.WriteLine(message);}フィールドは、オブジェクトの内部に値を保存します。
private string message = "";プロパティは、主にクラス内の値を取得・設定するための窓口です。
public string Message { get; set; } = "";それぞれの役割を整理すると、次のようになります。
ローカル変数:メソッド内の一時的なデータ
フィールド:クラスやオブジェクトが保持するデータ
プロパティ:データを取得・設定するための公開窓口
プロパティは利用時には変数のように見えますが、getやsetの処理が実行される点を覚えておきましょう。
8. C#プロパティに関するよくある質問
8-1. プロパティとフィールドはどちらを使うべき?
クラスの内部だけで利用する値には、基本的にprivateフィールドを使用します。クラスの外部に公開する値には、プロパティを使用するのが一般的です。
private int age;public int Age{get{return age;}set{age = value;}}
特別な処理が必要なければ、自動実装プロパティを使用できます。
public int Age { get; set; }外部向けのデータをpublicフィールドとして直接公開するよりも、プロパティを使ったほうが、後からアクセス制限や検証処理を追加しやすくなります。
8-2. getだけのプロパティは何に使う?
getだけのプロパティは、外部に値を公開しながら、自由な変更を防ぐために使います。
public class Order{public decimal UnitPrice { get; set; }public int Quantity { get; set; }public decimal TotalPrice => UnitPrice * Quantity;
}
TotalPriceは計算結果なので、外部から設定させる必要がありません。
また、コンストラクタで設定した後に変更させたくない値にも利用できます。
public class User{public int Id { get; }public User(int id){Id = id;}
}
IDや計算結果、作成後に変わらない情報などに適しています。
8-3. setを省略するとどうなる?
setを省略すると、プロパティを参照できる場所から値を読み取ることはできますが、通常はそこから代入できなくなります。
public string Name { get; }次のコードで値を取得できます。
Console.WriteLine(user.Name);しかし、外部からの代入はできません。
user.Name = "田中";値はコンストラクタなどで設定できます。
public class User{public string Name { get; }public User(string name){Name = name;}
}
値を外部から変更させたくない場合は、setを省略するか、private setを利用します。
public string Name { get; private set; } = "";8-4. 自動実装プロパティは初心者でも使ってよい?
自動実装プロパティは、初心者でも積極的に使って問題ありません。
public string Name { get; set; } = "";public int Age { get; set; }値をそのまま保存・取得するだけなら、自動実装プロパティのほうが簡潔で読みやすくなります。
ただし、getとsetの仕組みを理解するために、最初は通常のプロパティも書いてみることをおすすめします。
private string name = "";public string Name{get{return name;}set{name = value;}}
このコードが自動実装プロパティによって簡略化されることを理解できれば、状況に応じて正しく使い分けられるようになります。
8-5. プロパティはいつ使うのが正解?
プロパティは、クラスが持つ状態や情報を外部に公開するときに使用します。
たとえば、次のようなデータです。
ユーザーの名前や年齢
商品名や価格
注文の状態
ゲームキャラクターのレベル
図形の幅や高さ
計算された合計金額
単純に値を保存・取得する場合は、自動実装プロパティを使います。
public string Name { get; set; } = "";値の検証や加工が必要な場合は、通常のプロパティを使います。
private int age;public int Age{get{return age;}set{if (value < 0){throw new ArgumentOutOfRangeException(nameof(value));}
age = value;}
}
外部から変更させたくない場合は、getだけ、またはprivate setを使います。
public int Id { get; }public int Score { get; private set; }クラスの状態を表す値はプロパティ、明確な処理や動作はメソッド、と考えると使い分けやすくなります。
まとめ
C#のプロパティは、クラスが持つ値を安全に取得・設定するための仕組みです。
getアクセサは値を取得するとき、setアクセサは値を設定するときに実行されます。setアクセサ内のvalueには、プロパティへ代入された値が渡されます。
基本的なプロパティは次のように記述します。
private string name = "";public string Name{get{return name;}set{name = value;}}
特別な処理が不要であれば、自動実装プロパティを使うと簡潔です。
public string Name { get; set; } = "";外部から値を変更させたくない場合は、getだけのプロパティやprivate setを利用できます。
public int Id { get; }public int Score { get; private set; }プロパティを使うと、フィールドを外部から隠しながら、値の検証、アクセス制限、計算結果の公開などを実現できます。
最初は「値をそのまま扱うなら自動実装プロパティ」「独自の処理が必要なら通常のプロパティ」と覚えるとよいでしょう。実際にクラスを作りながら、get、set、private set、読み取り専用プロパティを使い分けることで、C#プロパティへの理解が深まります。

