005.4.プロパティとは

過去のブログのアーカイブ
この記事は前身のブログのアーカイブを引き継いだものです. 画像が正しく表示できないなど,コンテンツの表示に問題がある恐れがあります.

プロパティは大雑把に言えば変数の進化系みたいなものです。変数ではただ単純にデータを格納するだけの存在でしたが、プロパティではそのデータを加工するとともに情報を返すということができるのです。

変数は単純な話

例えば、変数の場合はこのようになります。至極当たり前なことなのですが

public class A {
    public int Value = 10;
}
public void Main() {
    A c1 = new A();
    c1.Value = 20;
    // c1.Value => 20
}

当たり前なことなのですが、「変数に数値を格納する」命令をすれば、その数値がちゃんと格納されます。
そして格納した数値を取得しようとすれば、格納された数値が出てくるのです。
なぜこのような当たり前の話をしているかというと、プロパティはそうとも限らないからなのです。

プロパティは加工されたデータを扱える

プロパティは内部にメソッドを持っています。メソッドと違って、パラメータを指定する必要がない場合にプロパティが利用されます。
例えば、先ほどのクラスでValueの値にプラス1するメソッドを書いてみましょう。

public class A {
    public int Value = 10;
    public int GetPlusOne() {
        return this.Value + 1;
    }
}
public void Main() {
    A c1 = new A();
    c1.Value = 20;
    // Output: 21
    Console.WriteLine( c1.GetPlusOne() );
    // c1.Value => 20
}

単純に1プラスされた値を返すメソッド(GetPlusOne)を定義してみました。書いてる通り、1プラスされた値が返ってきます。
ただ、元のValue変数の値は変更されていませんん。あくまでプラス1された値が返ってくるだけです。
これをプロパティを利用して取得してみましょう。

public class A {
    public int Value = 10;
    public int PlusOne {
        get {
            return this.Value + 1;
        }
    }
}
public void Main() {
    A c1 = new A();
    c1.Value = 20;
    // Output: 21
    Console.WriteLine( c1.PlusOne );
    // c1.Value => 20
}

プロパティの特徴はパラメータを持たない、そして{ 〜 } の中にgetやらsetやら置かれます。(省略可能)
このプロパティを呼び出すときは、パラメータを指定せずに変数を呼び出すみたいに、呼び出すことができます。
なお、プロパティに値をセットする際も、似たようなことができます。

public class A {
    public string Message = "";
    public string Name {
        set {
            this.Message = "Hello, " + value;
        }
    }
}
public void Main() {
    A c1 = new A();
    c1.Name = "Yamada";
    // Output: Hello, Yamada
    Console.WriteLine( c1.Message );
    // c1.Name => getが指定されてないので使えない
}

これは「Nameに文字列を代入したら、Message変数に”Hello, “をつけて代入」するというプロパティです。(ちょっとあんまりいい例ではないですが)
プロパティに値が代入されたら、プロパティのsetではvalue変数として読み取ることができます。

まとめ

プロパティは変数とメソッドのバイブリットみたいなものです。

余談

クラスではpublicの変数を置くべきではない

サンプルとして、クラスに直接publicの変数を置いたものをたくさん載せましたが、これはあまりよろしくないのです。
と言いますのも、クラスは「中のみ使える!」「外からでも使える!」というのをきっちり住み分けする傾向にあります。
個人で開発する際にはあまり問題ないかもしれないですが、このように書くのが適切です。

// よろしくない例
public class A {
    public int Value;
}
// いい例
public class A {
    public int Value { get; set; }
}

実はこのように、getとsetのブロックを省略することができます。ただしこの場合はgetとsetが両方ある必要があり、省略することはできません。
なお、このような書き方すると、動作は変数と全く同じです。ですが、面倒かもしれないですが、変数を直接publicで置くのは控えましょう。

この理由

このような面倒なルールになっているには幾つか理由がありますが、バグ取りをしやすくするためというのが大きな理由となっています。
変数に格納したのは誰だ!みたいな犯人探しは難しいのですが、プロパティに代入しようとしたやつは誰だ!と追跡するのは比較的簡単です。

getとsetは別のアクセス修飾子を設定できる

また、setとgetはそれぞれ別のアクセス修飾子を指定することができるので、このような書き方も有効です。

public class A {
    public int Value { get; private set; }
    public void Test() {
    // できる
    Console.WriteLine (A.Value );
    // できる
    this.A = 10;
    }
}
public class B {
    public void Test() {
    A v1 = new A();
    // できる
    Console.WriteLine( v1.Value );
    // AのValueのsetはprivateなので、別のクラスからはアクセスできない
    v1.Value = 20;
    }
}

このように、変数みたいなものだけど、外からは取得できないよ。みたいなプロパティも作ることができるのです。