フィールドとプロパティ ― はじめて学ぶ人のための基礎まとめ
目次
1. 用語の整理
用語 | ひと言で | どこで定義する? | 何のため? |
---|---|---|---|
フィールド (field) | “値をしまう箱” | クラスの中でメンバ変数として宣言 | 内部データを保持する |
プロパティ (property) | “箱に出入口を付けたもの” | クラスの中で Type 名前 { get; set; } の形で宣言 | フィールドへの安全なアクセス窓口 |
イメージ
- フィールド = 倉庫の中身そのもの
- プロパティ = 倉庫の搬入口(受付で検品や記録ができる)
2. なぜプロパティを使うのか
- カプセル化
- クラス外から 直接 値を触らせず、「操作方法」を制御できます。
- 不正値のブロック
- set 内にチェックを入れて「0〜100 以外は受け付けない」などのバリデーションが可能。
- 読み取り専用・書き込み専用が選べる
- 例:public int Id { get; } なら外部は読み取りだけ。
- あとから内部構造を変えても呼び出し側は影響なし
- 最初はフィールド直結 → 後で計算式に変更してもプロパティ名は同じなので既存コードが壊れません。
- デバッグ・ロギング・通知が入れられる
- 例:WPF や Unity の INotifyPropertyChanged でデータバインディング。
3. 書き方のバリエーション
3-1. フィールド
public class Player
{
// 外部から直接読める・書ける(丸裸)
public int Score;
}
3-2. 自動実装プロパティ(最もシンプル)
public class Player
{
// 裏でフィールドが自動生成される
public int Score { get; set; }
}
3-3. バリデーション付きプロパティ
public class Player
{
private int _score; // 実体(private フィールド)
public int Score // 公開窓口
{
get => _score;
set
{
if (value < 0) value = 0; // マイナスは許さない
_score = value;
}
}
}
using System;
public class Player
{
// ───────── フィールド(実体)─────────
// 外部に直接さらさず、クラスの内部データを保持する場所。
private int _score;
// ───────── プロパティ(公開窓口)─────────
// ・get … 現在のスコアをそのまま返す。
// ・set … 受け取った値を検査し、マイナスなら 0 に補正して保存する。
public int Score
{
get => _score;
set
{
// ① バリデーション:あり得ない値は修正または拒否
if (value < 0) value = 0;
// ② フィールドへ保存
_score = value;
}
}
}
使い方サンプル
class Program
{
static void Main()
{
// プレイヤー生成
var p = new Player();
// スコアを加算してみる
p.Score = 150;
Console.WriteLine($"現在のスコア: {p.Score}"); // → 150
// 間違ってマイナスを入れても…
p.Score = -42; // set 内で 0 に補正
Console.WriteLine($"現在のスコア: {p.Score}"); // → 0
}
}
実行するとどうなる?
現在のスコア: 150
現在のスコア: 0
- p.Score = -42; を書いても、プロパティの set ブロック で自動的に 0 に補正されるため※バグの混入を未然に防げる。
- 呼び出し側は スコアが負にならない という前提でロジックを書けるため、コード全体の安全性が向上 する。
3-4. 読み取り専用プロパティ
public class Player
{
private readonly string _id = Guid.NewGuid().ToString();
public string Id => _id; // 式形式 (C#6 以降)
}
4. コーディング規約のポイント(C# の慣例)
項目 | 推奨スタイル |
---|---|
フィールド名 | 先頭小文字のキャメルケース + 前に _ を付ける例:_health |
プロパティ名 | 先頭大文字のパスカルケース例:Health |
公開範囲 | 原則:フィールドは private、外部公開はプロパティで |
5. 使い分け早見表
こう思ったら… | 選択肢 |
---|---|
「ただの内部データで外に見せない」 | private フィールド |
「外部に読ませたい/書かせたい」 | プロパティ |
「外部に読ませるだけ」 | get のみプロパティ |
「セット時に制限・通知したい」 | バリデーション付きプロパティ |
「全く制御不要、PoC やスクリプトで簡単に」 | (Unity の public フィールドなど、例外的に許容) |
6. 例題:年齢を持つ Student クラス
public class Student
{
private int _age;
/// <summary>
/// 0~120 以外は拒否する年齢プロパティ
/// </summary>
public int Age
{
get => _age;
set
{
if (value is < 0 or > 120)
throw new ArgumentOutOfRangeException(nameof(value), "年齢は 0~120 の範囲で指定してください。");
_age = value;
}
}
}
public class Student
{
private int _age;
/// <summary>
/// 0~120 以外は拒否する年齢プロパティ(従来構文版)
/// </summary>
public int Age
{
get => _age;
set
{
// パターン構文 (value is < 0 or > 120) を
// 従来の比較演算子 + 論理演算子で書き換えた例
if (value < 0 || value > 120)
throw new ArgumentOutOfRangeException(
nameof(value),
"年齢は 0~120 の範囲で指定してください。");
_age = value;
}
}
}
変更ポイント
箇所 | パターン構文 | 従来構文 |
---|---|---|
範囲チェック | value is < 0 or > 120 | value < 0 |
論理演算子 | or (C# 9~) | |
型チェック | ― | ―(今回不要) |
このように、パターン マッチングの relational + logical pattern は、従来構文では単純な大小比較と ||(or)で等価に書けます。
var s = new Student();
s.Age = 25; // OK
s.Age = -1; // 例外発生
7. 練習問題(10 分)
- Temperature クラスを作り、摂氏温度 Celsius をプロパティで保持しなさい。
- Fahrenheit 読み取り専用プロパティを追加し、華氏に変換して返しなさい。
- ヒント:F = C * 9 / 5 + 32
- Celsius に −273.15 未満が設定されたら例外を出すようにしなさい。
Temperature クラス — サンプル解答
using System;
public class Temperature
{
// ───────────────────────────────
// 1. 摂氏温度を保持するプロパティ
// ・値は -273.15 ℃ 以上でなければならない
// ───────────────────────────────
private double _celsius; // 実体フィールド(private)
public double Celsius
{
get => _celsius;
set
{
if (value < -273.15)
throw new ArgumentOutOfRangeException(
nameof(value),
"摂氏温度は -273.15 ℃ 以上でなければなりません。");
_celsius = value;
}
}
// ───────────────────────────────
// 2. 華氏温度を返す読み取り専用プロパティ
// F = C * 9 / 5 + 32
// ───────────────────────────────
public double Fahrenheit => _celsius * 9 / 5 + 32;
// ───────────────────────────────
// 便利なコンストラクタ(任意)
// ───────────────────────────────
public Temperature(double celsius) => Celsius = celsius;
public override string ToString()
=> $"{Celsius:F2} ℃ / {Fahrenheit:F2} ℉";
}
使い方例
class Program
{
static void Main()
{
var t = new Temperature(25); // 25 ℃
Console.WriteLine(t); // 25.00 ℃ / 77.00 ℉
t.Celsius = -10; // OK
Console.WriteLine(t); // -10.00 ℃ / 14.00 ℉
// 下面は絶対零度以下なので例外
t.Celsius = -300; // throws ArgumentOutOfRangeException
}
}
解説ポイント
- バリデーションCelsius の set で −273.15 未満を弾き、ArgumentOutOfRangeException を投げています。
- 読み取り専用プロパティFahrenheit は => 式形式で計算結果を直接返します(C# 6 以降)。
- 設計意図
- フィールド _celsius はカプセル化し、直接操作させません。
- ToString() をオーバーライドするとデバッグ時や Console.WriteLine() が便利になります。
これで 3 つの要件すべてを満たす実装となります。
8. まとめ
- フィールド = データの実体。外には極力隠す。
- プロパティ = フィールドへの“扉”。安全・柔軟・変更に強い。
- まずは「外部公開=プロパティ」と覚え、必要に応じてバリデーションや読み取り専用を追加しましょう。
次のステップ
- 自動実装プロパティの初期値設定(C# 6 の式形式)
- readonly / init アクセサ(C# 9 以降)
- 変更通知 (INotifyPropertyChanged) を用いた MVVM 入門
訪問数 3 回, 今日の訪問数 3回
ディスカッション
コメント一覧
まだ、コメントがありません