閉じる

C#のプロパティの基本 { get; set; } の使い方をやさしく解説

C#のプロパティは、クラスのデータを安全かつわかりやすく扱うための仕組みです。

中でも{ get; set; }は、値の取得と代入を定義する基本形で、初心者にとって最初に覚えるべき重要な構文です。

本記事では、プロパティの基本、書き方、実用パターン、初期化と活用まで、やさしく段階的に解説します。

C#のプロパティとは { get; set; } の基本

プロパティの役割とフィールドの違い

プロパティは、クラスの内部データ(フィールド)へのアクセス方法を提供する「窓口」です。

直接フィールドを公開すると、予期しない値の代入や整合性の崩れが起こりやすくなります。

そこでプロパティで受け口を定義し、必要なら検証や変換を挟むことで、安全かつ意図が伝わるAPIになります。

以下の表は、フィールドとプロパティの違いを簡潔にまとめたものです。

項目フィールドプロパティ
役割値そのものの保管場所値の取得/設定のインターフェース
アクセス制御直接アクセスになりやすいget/setで制御や検証が可能
互換性リファクタリングで破綻しやすい実装の変更に強い(内部の保持方法を変えやすい)
シリアライゼーション種類により挙動が変わる属性で制御しやすい
命名_camelCaseなどPascalCase(例: Name, Age)

基本方針として、外部に公開するのはプロパティ、内部の格納はフィールドと覚えておくとよいです。

get と set の意味

  • get: 値を取得する処理です。呼び出し側から見ると「読み取り」です。
  • set: 値を代入するときの処理です。代入前に検証や正規化を行えます。

手動でフィールドを用意してプロパティを構築する例を示します。

C#
// 手動実装プロパティの例
public class Person
{
    // バッキングフィールド(backing field)
    private string _name = "Unknown";

    // プロパティ
    public string Name
    {
        get
        {
            // 取得時にそのまま返す例
            return _name;
        }
        set
        {
            // 代入時にnullや空文字を許さない
            if (string.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentException("Nameは空にできません。");
            }
            _name = value.Trim();
        }
    }
}

初心者が押さえる使い方のコツ

プロパティは文法が簡潔ですが、目的は「安全で意図が明確なデータアクセス」です。

最初は自動実装プロパティから始め、必要になったら手動実装に切り替えるのがおすすめです。

外部公開はプロパティ、内部データはフィールドという棲み分けを守ると、拡張や保守が楽になります。

自動実装プロパティの書き方

基本の宣言 { get; set; } の使い方

自動実装プロパティは、バッキングフィールドを自動生成してくれる構文です。

簡潔に書けるため、最初の一歩に最適です。

C#
using System;

public class Person
{
    // 自動実装プロパティ(バッキングフィールドはコンパイラが自動生成)
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Program
{
    public static void Main()
    {
        var p = new Person();
        p.Name = "Taro";
        p.Age = 20;

        Console.WriteLine($"Name: {p.Name}, Age: {p.Age}");
    }
}
実行結果
Name: Taro, Age: 20

既定値の初期化

C# 6以降は、プロパティに初期値を直書きできます。

コンストラクタを書かずにデフォルトを設定でき、初学者にも扱いやすいです。

C#
public class Account
{
    public string Owner { get; set; } = "Guest";  // 既定値
    public decimal Balance { get; set; } = 0m;    // 既定値
}
C#
using System;

public class Program
{
    public static void Main()
    {
        var a = new Account();
        Console.WriteLine($"Owner: {a.Owner}, Balance: {a.Balance}");

        var b = new Account { Owner = "Hanako", Balance = 1500m };
        Console.WriteLine($"Owner: {b.Owner}, Balance: {b.Balance}");
    }
}
実行結果
Owner: Guest, Balance: 0
Owner: Hanako, Balance: 1500

プロパティ名の命名ルール

プロパティ名はPascalCaseにします(例: Name, CreatedAt)。

内部のバッキングフィールドは_camelCaseが一般的です(例: _name)。

この統一は可読性を大きく高めます。

get と set の実用パターン

値を取得する get

計算結果を返す「読み取り専用」プロパティは便利です。

フィールドを持たず、他プロパティから派生した値をまとめて返せます。

C#
using System;

public class Rectangle
{
    public double Width  { get; set; }
    public double Height { get; set; }

    // 計算プロパティ(読み取り専用)
    public double Area
    {
        get
        {
            return Width * Height; // 面積を毎回計算して返す
        }
    }
}

public class Program
{
    public static void Main()
    {
        var r = new Rectangle { Width = 3, Height = 4 };
        Console.WriteLine($"Area: {r.Area}");
        r.Width = 10;
        Console.WriteLine($"Area after resize: {r.Area}");
    }
}
実行結果
Area: 12
Area after resize: 40

値を代入する set

代入時の検証(バリデーション)はsetで行います。

入力をTrimしたり範囲をチェックして、不正値を拒否できます。

C#
using System;

public class Product
{
    private string _name = "Unnamed";
    private decimal _price;

    public string Name
    {
        get => _name;
        set
        {
            if (string.IsNullOrWhiteSpace(value))
                throw new ArgumentException("Nameは空白不可です。");
            _name = value.Trim(); // 余分な空白を除去
        }
    }

    public decimal Price
    {
        get => _price;
        set
        {
            if (value < 0m)
                throw new ArgumentOutOfRangeException(nameof(value), "Priceは0以上にしてください。");
            _price = value;
        }
    }
}

public class Program
{
    public static void Main()
    {
        var p = new Product();
        p.Name = "  Coffee  "; // setでTrim
        p.Price = 250m;
        Console.WriteLine($"{p.Name} - {p.Price}円");
    }
}
実行結果
Coffee - 250円

簡単なチェックで不正値を防ぐ

最小限のチェックでも効果は大きいです。

例えば年齢を0以上に制限するなど、ドメインの前提条件をプロパティで守ると、後工程での不具合を減らせます。

C#
public class Member
{
    private int _age;
    public int Age
    {
        get => _age;
        set
        {
            // 不正値を受け取らない
            if (value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Ageは0以上です。");
            _age = value;
        }
    }
}

読み取り専用にする private set

外部からは読み取りだけ許し、クラス内部だけが更新できるようにするにはprivate setを使います。

更新タイミングを制御したい「現在状態」や「更新日時」に適します。

C#
using System;

public class Order
{
    public string Number { get; }
    public DateTime CreatedAt { get; } = DateTime.UtcNow;

    // 外部からは読み取り専用、内部では更新可能
    public DateTime LastUpdated { get; private set; } = DateTime.UtcNow;

    public Order(string number)
    {
        Number = number ?? throw new ArgumentNullException(nameof(number));
    }

    public void UpdateSomething()
    {
        // 何らかの更新処理...
        LastUpdated = DateTime.UtcNow; // 内部でのみ更新
    }
}

public class Program
{
    public static void Main()
    {
        var o = new Order("A-001");
        Console.WriteLine($"CreatedAt: {o.CreatedAt:O}");
        Console.WriteLine($"LastUpdated: {o.LastUpdated:O}");

        o.UpdateSomething();
        Console.WriteLine($"LastUpdated(after): {o.LastUpdated:O}");
    }
}
実行結果
CreatedAt: 2025-09-12T03:55:03.0855286Z
LastUpdated: 2025-09-12T03:55:03.0855512Z
LastUpdated(after): 2025-09-12T03:55:03.0884391Z

public setの乱用は意図しない変更につながります。

必要がなければprivate setやgetのみで最小公開にしましょう。

プロパティの初期化と活用例

クラスの作り方とインスタンス生成での流れ

C#ではクラス(class)にプロパティを定義し、newでインスタンス(オブジェクト)を生成して使います。

初期値はプロパティ初期化子、コンストラクタ、オブジェクト初期化子のいずれかで与えられます。

状況に応じて使い分けるのがポイントです。

コンストラクタでプロパティを初期化

必須項目がある場合、コンストラクタで初期化を強制します。

こうすると「必ず埋まっている」という前提を保てます。

C#
using System;

public class User
{
    // 必須項目はgetのみ(読み取り専用)にし、コンストラクタで設定
    public string Id { get; }
    public string Name { get; private set; }

    // 任意項目は既定値を設定しておく
    public string Email { get; set; } = "unset@example.com";

    public User(string id, string name)
    {
        // 簡単な引数チェック
        if (string.IsNullOrWhiteSpace(id)) throw new ArgumentException("Idは必須です。");
        if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Nameは必須です。");

        Id = id.Trim();
        Name = name.Trim();
    }

    public void Rename(string newName)
    {
        if (string.IsNullOrWhiteSpace(newName)) throw new ArgumentException("Nameは空にできません。");
        Name = newName.Trim();
    }
}

public class Program
{
    public static void Main()
    {
        var u = new User("u-100", "Sakura");
        Console.WriteLine($"{u.Id}: {u.Name}, {u.Email}");
        u.Rename("Sakura Tanaka");
        Console.WriteLine($"{u.Id}: {u.Name}, {u.Email}");
    }
}
実行結果
u-100: Sakura, unset@example.com
u-100: Sakura Tanaka, unset@example.com

オブジェクト初期化子でまとめて設定

プロパティをまとめて初期化するにはオブジェクト初期化子が便利です。

読みやすく、初期化コードを簡潔にできます。

C#
using System;
using System.Collections.Generic;

public class Book
{
    public string Title  { get; set; } = "Untitled";
    public string Author { get; set; } = "Unknown";
    public int    Year   { get; set; } = 0;
}

public class Program
{
    public static void Main()
    {
        // オブジェクト初期化子で一括設定
        var b1 = new Book { Title = "C#入門", Author = "Yamada", Year = 2025 };
        var b2 = new Book { Title = "やさしいOOP", Author = "Sato" }; // Yearは既定値

        // コレクション初期化子と併用する例
        var shelf = new List<Book>
        {
            new Book { Title = "LINQ実践", Author = "Kato", Year = 2024 },
            b1,
            b2
        };

        foreach (var b in shelf)
        {
            Console.WriteLine($"{b.Title} by {b.Author} ({b.Year})");
        }
    }
}
実行結果
LINQ実践 by Kato (2024)
C#入門 by Yamada (2025)
やさしいOOP by Sato (0)

ヒント: 既定値(初期化子)とオブジェクト初期化子を組み合わせると、必要な部分だけを上書きでき、コードの意図が明確になります。

どの初期化方法を選ぶべきかの目安

  • 必須項目: コンストラクタで要求する(未設定を防ぐ)。
  • 任意項目: プロパティの既定値でカバーし、必要に応じて上書き。
  • 多数の任意項目を一度に設定: オブジェクト初期化子で簡潔に。

一貫した初期化方針をチーム内で決めておくと、保守が楽になります。

まとめ

本記事では、C#のプロパティ { get; set; }を、役割の理解から自動実装、検証を伴う実用パターン、そして初期化の実践まで解説しました。

外部公開はプロパティ、内部保持はフィールドという原則を守り、必要に応じてprivate setや計算プロパティを活用すると、堅牢で読みやすいコードになります。

まずは自動実装プロパティでシンプルに始め、要件が増えたら手動実装や検証を組み込んでいきましょう。

この記事を書いた人
エーテリア編集部
エーテリア編集部

C#の入門記事を中心に、開発環境の準備からオブジェクト指向の基本まで、順を追って解説しています。ゲーム開発や業務アプリを目指す人にも役立ちます。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!