TomoProgの技術書

底辺プログラマーが達人プログラマーになるまで

自動実装プロパティを読み取り専用にする方法

皆さん
こんにちは、こんばんは
TomoProgです。

気づけば2ヶ月以上更新してなかったですが、
久しぶりに更新していきましょう!

今回はC#のプロパティを読み取り専用にする方法が分かったので、
そのことを書いていこうと思います。

それでは頑張っていきましょう。

【重要】
今回紹介するやり方はC#6.0以前のバージョンでの使用方法です。
C#6.0から読み取り専用の自動実装プロパティを定義出来る構文が追加されています。

プロパティを使ってメンバーにアクセスする

C#にはクラスのメンバーにアクセスしたいとき、
プロパティを介してアクセスするということがよくあります。

public class Human
{
    /// <summary>名前</summary>
    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
        }
    }

    /// <summary>年齢</summary>
    private int _age;
    public int Age
    {
        get
        {
            return _age;
        }
        set
        {
            if(value > 99)
            {
                value = 99;
            }
            _age = value;
        }
    }
}
class MainClass
{
    public static void Main(string[] args)
    {
        Human h1 = new Human();
        h1.Name = "Yamada";
        h1.Age = 22;

        Human h2 = new Human();
        h2.Name = "Sato";
        h2.Age = 100;

        Console.WriteLine("h1.Name:{0} h1.Age:{1}", h1.Name, h1.Age);
        Console.WriteLine("h2.Name:{0} h2.Age:{1}", h2.Name, h2.Age);
    }
}
実行結果:
h1.Name:Yamada h1.Age:22
h2.Name:Sato h2.Age:99

プロパティである「Name」と「Age」を介してprivate変数へアクセスしています。

プロパティを使うメリットは
値に応じて処理を記述できる
ということです。

今回はAgeプロパティに99より大きい値を入れられた場合は
99に補正するようにsetを定義しています。

このようにget、setの中に処理を記述することで
整合性チェックなどの処理を逐次書かなくても
クラスを安全に使用することができます。

自動実装プロパティを使う

get、setの中に処理を記述するのであればこの書き方は良いのですが、
Nameプロパティのように値を取得、設定するだけの場合は
いちいちget、setを書くのは正直面倒です。

そんなときは自動実装プロパティを使用すると簡単に書くことが出来ます。

/// <summary>
/// 人間クラス
/// </summary>
public class Human
{
    /// <summary>名前/summary>
    public string Name { get; set; }
    
    /// <summary>年齢</summary>
    private int _age;
    public int Age
    {
        get
        {
            return _age;
        }
        set
        {
            if(value > 99)
            {
                value = 99;
            }
            _age = value;
        }
    }
}

変更された点はNameのプロパティ定義です。
private変数の記述が不要になり、
Nameプロパティだけで先程の例と同じように使用することが出来ます。
(実際には自動的にprivateのメンバーが生成されているらしいですが、そのあたりは今回は触れません。)

自動実装プロパティで読み取り専用にしたい

さて、自動実装プロパティの使い方も分かったところでようやく今回の本題です。

例えばこのクラスに血液型を追加で持たせたとします。

名前や年齢は変わるものですが、血液型は変わらないので、
変更出来ないように読み取り専用にしておきたいです。

というわけで、getだけを持つ血液型プロパティを記述してみたいと思います。

/// <summary>
/// 人間クラス
/// </summary>
public class Human
{
    /// <summary>名前</summary>
    public string Name { get; set; }
    
    /// <summary>血液型</summary>
    public string Blood { get; }
    
    /// <summary>年齢</summary>
    private int _age;
    public int Age
    {
        get
        {
            return _age;
        }
        set
        {
            if(value > 99)
            {
                value = 99;
            }
            _age = value;
        }
    }

    /// <summary>
    /// コンストラクタ
    /// </summary>
    public Human(string name, int age, string blood)
    {
        Name = name;
        Age = age;
        Blood = blood;
    }
}

こんな感じで血液型プロパティを追記しました。

ついでに人間クラスを作るときに名前、年齢、血液型を
指定できるようにコンストラクタを記述したので、
それに応じてメインクラスも書き換えます。

class MainClass
{
    public static void Main(string[] args)
    {
        Human h1 = new Human("Yamada", 22, "A");
        Human h2 = new Human("Sato", 100, "B");

        Console.WriteLine("h1.Name:{0} h1.Age:{1} h1.Blood:{2}", h1.Name, h1.Age, h1.Blood);
        Console.WriteLine("h2.Name:{0} h2.Age:{1} h2.Blood:{2}", h2.Name, h2.Age, h2.Blood);
    }
}

これで血液型はクラス作成時から変更できない
読み取り専用のプロパティとして定義出来たはず。

しかし、コンパイルしてみると、
Bloodプロパティは読み取り専用なので
クラス内でも代入できないと言われてしまいます。

実はBloodプロパティを以下のように変更するだけで
簡単に読み取り専用に出来てしまいます。

/// <summary>血液型</summary>
public string Blood { get; private set; }

これで実際に実行すると

h1.Name:Yamada h1.Age:22 h1.Blood:A
h2.Name:Sato h2.Age:100 h2.Blood:B

実行結果が表示されました。

メインクラス内でBloodプロパティに設定しようと
以下のようなコードを記述すると、

class MainClass
{
    public static void Main(string[] args)
    {
        Human h1 = new Human("Yamada", 22, "A");
        h1.Blood = "B";
    }
}

コンパイル時にsetアクセサーにアクセスできないと言われるため、
メインクラスからの設定は出来なくなります。

これで自動実装プロパティを読み取り専用にすることが出来ました!!

まとめ

自動実装プロパティは
public <型> <プロパティ名> { get; private set; }
で読み取り専用に出来る。

今回は自動実装プロパティを読み取り専用にする方法を書いていきました。
アクセスレベルを制限することで、安全にクラスを使っていきましょう。

それではまた。

TomoProg

GitHub
TomoProg (TomoProg) · GitHub

Twitter
TomoProg (@tomoprog_xxx) | Twitter