前回は「クラス(データと処理をまとめた設計図)」をやりました。

今回は、クラスが持つデータの話。フィールドプロパティです。少し細かい話ですが、データを「安全に」扱うための、大事な仕組みです。

フィールドはクラスが持つデータそのもの、プロパティはそれを安全に出し入れする窓口です。

フィールド ── クラスが持つデータ

前回、クラスの中に書いたこれ。

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

この NameAge のような、クラスが持つデータのことを、フィールドと呼びます。前回から、もう使っていたんですね。

フィールドは、そのまま読み書きできます。

Person taro = new Person();
taro.Age = 20;                // 書き込み
Console.WriteLine(taro.Age);  // 読み出し

便利ですが、ここに、ちょっとした問題があります。

そのままだと、変な値も入ってしまう

フィールドは、そのままだとどんな値でも入ってしまいます

taro.Age = -5;     // 年齢がマイナス?
taro.Age = 9999;   // 年齢が9999歳?

ありえない値ですが、プログラム上は止められません。年齢に -5 や 9999 が入っても、エラーにならず、そのまま通ってしまう。

これは、けっこう危険です。おかしなデータが紛れ込むと、後でバグの原因になります。

おかしな値が入らないように、見張りをつけたい」。そこで登場するのが、プロパティです。

プロパティ ── データの出入りを見張る窓口

プロパティは、データを出し入れするときに、間に入ってチェックする窓口です。

料理でいうなら、受付係のようなもの。「この食材、傷んでないか確認してから、中に入れますね」と、間でチェックしてくれる人です。

書き方を見てみます。年齢に、変な値が入らないようにしたプロパティです。

class Person
{
    private int age;   // 実際のデータ(外から直接さわれない)

    public int Age     // 窓口(プロパティ)
    {
        get { return age; }            // 読むとき
        set
        {
            if (value >= 0)            // 0以上のときだけ
            {
                age = value;           // 受け入れる
            }
        }
    }
}

少し長いですが、ポイントだけ押さえれば大丈夫です。

  • private int age … 本当のデータ。private なので外から直接さわれない
  • public int Age … 外から使う窓口(プロパティ)
  • get … 値を読むときの処理
  • set … 値を書くときの処理。ここでチェックできる
  • value … 外から入れようとした値が、ここに入っている

set の中で「0以上のときだけ受け入れる」とチェックしているので、マイナスの値は弾かれます。

taro.Age = 20;    // 0以上なのでOK
taro.Age = -5;    // 弾かれる(age は変わらない)

使う側は、フィールドのときとまったく同じ書き方です。でも裏で、こっそり見張りが働いている。これがプロパティの便利なところです。

なぜ「直接さわれない」ようにするのか

ここで、第17回(スコープ)で少し触れた publicprivate が効いてきます。

  • public … 外から使える
  • private … 外から使えない(クラスの中だけ)

本当のデータ ageprivate にして隠しpublic のプロパティ Age だけを窓口として開ける

こうすると、外からは必ず窓口(プロパティ)を通ることになります。窓口でチェックしているので、変な値は入れません。

データを隠して、決まった窓口だけ開ける。この考え方をカプセル化と呼びます。オブジェクト指向の、大事な考え方のひとつです。

短く書く方法もある

毎回こんなに長く書くのは大変です。チェックがいらない単純な場合は、短く書けます。

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

{ get; set; } と書くだけ。「読み書きできる窓口」を、簡単に用意できます。実際の開発では、この短い書き方をよく使います。

まずは「フィールドは生のデータ、プロパティはチェックできる窓口」という考え方をつかんでおけば十分です。

つまずきポイント

混乱しやすいのが、フィールドとプロパティの名前です。

慣習として、

  • フィールド(隠す方)… 小文字で始める(age
  • プロパティ(窓口)… 大文字で始める(Age

名前を変えて区別します。同じ「年齢」でも、age(生データ)と Age(窓口)は別物だと意識すると、混乱しません。

まとめ

フィールドは生のデータ、プロパティはそれを安全に扱う窓口。

  • フィールド … クラスが持つデータそのもの
  • プロパティget(読む)と set(書く)で、出入りをチェックできる窓口
  • データを private で隠し、窓口だけ開けるのが カプセル化
  • 単純なら { get; set; } で短く書ける

次回は、クラスの中に「処理」を持たせる、クラスの中のメソッド です。