Top > Programming > .NetFramework > Tips > InitStructure'sPropertyInConstructor
Last-modified: Mon, 02 Dec 2013 05:20:50 JST
Counter:4509 Today:1 Yesterday:0 Online:8
このエントリーをはてなブックマークに追加

構造体の Property をコンストラクタから初期化する

About

C# では構造体もプロパティを持つことができます。しかしながら構造体におけるプロパティは、コンストラクタでその値を初期化するときに問題を起こす可能性があります。

構造体はコンストラクタですべてのフィールドが初期化される必要があります。すべてのフィールドが初期化される前に this を使った代入や参照ができません。このような場合に次のエラーが発生します。"すべてのフィールドが割り当てられるまでは、'this' オブジェクトは使用できません。"ここではこの問題とその解決方法について解説します。

  • &ref(): File not found: "ConsoleApplication_InitStructProperty.zip" at page "Programming/.NetFramework/Tips/InitStructure'sPropertyInConstructor";
    • VisualStudio2012

問題が起きるパターン

次のような構造体を実装するとき問題が起きます。構造体 TestStructureA は、TestProperty プロパティを持っています。このプロパティは取得だけを許可して、コンストラクタによってのみ初期化することができるとします。このとき、コンストラクタでエラーが起きます。

struct TestStructureA
        {
            /// <summary>
            /// 取得だけを許可するプロパティです。
            /// </summary>
            public int TestProperty { get; private set; }

            /// <summary>
            /// TestProperty に任意の値を代入して初期化するコンストラクタです。
            /// </summary>
            /// <param name="value">
            /// TestProperty に代入する値を指定します。
            /// </param>
            public TestStructureA(int value)
            {
                TestProperty = value;
            }
        }

問題の解説

この問題が起きる理由は、プロパティの実装は実際には次のように処理されるためです。TestProperty プロパティを実装するとき、コンパイラは private なフィールド変数 (ここでは _TestProperty) を定義して、参照するような実装に変換してコンパイルします。

    private int _TestProperty;
    public TestProperty
    {
       get{ return this._testProperty; }
       set{ this._testProperty = value; }
    }

このとき、this が使われている点に注意してください。プロパティが実際にどのように処理されているかを理解することで、この問題の原因が分かり、解決することができます。

問題の解決

問題の解決は簡単です。アクセシビリティを変更したいプロパティを実装するとき、値を保存するためのフィールド変数を用意して、プロパティから参照するように実装すればよいです。次のソースコードは、先の TestStructureA を改善した例です。

struct TestStructureB
        {
            /// <summary>
            /// TestProperty の実体となるフィールドを定義します。
            /// </summary>
            private int testProperty;

            /// <summary>
            /// 取得だけを許可するプロパティです。
            /// </summary>
            public int TestProperty
            {
                get { return this.testProperty; } 
                private set { this.testProperty = value; }
            }

            /// <summary>
            /// TestProperty に任意の値を代入して初期化するコンストラクタです。
            /// </summary>
            /// <param name="value">
            /// TestProperty に代入する値を指定します。
            /// </param>
            public TestStructureB(int value)
            {
                //フィールドを初期化します。
                //プロパティによって set アクセサを隠ぺいできるようになります。
                testProperty = value;
            }
        }