« C# のための DirectX ライブラリ | メイン | ドット絵 マイ »

2006年04月21日

構造体を格納するプロパティ [C#]

C#のプロパティは、ユーザにより抽象的にオブジェクトにアクセスしてもらうためにとても有用な機能だ。しかしC#において、構造体とプロパティはとても相性が悪いことに気づいた。当たり前の事なのかもしれないが、結構これで悩んだので一応メモしておく。

このようなクラスがあるとする。

// 物体の大きさを2種類の方法で保存するクラス
class TestClass {

    // メンバ変数の "Size" 構造体
    public SizeStruct SizeStructMember = new SizeStruct();

    // メンバ変数の "Size" クラス
    public SizeClass SizeClassMember = new SizeClass();

    // プロパティの "Size" 構造体
    public SizeStruct SizeStructProp {
        get { return this.SizeStructMember; }
        set { this.SizeStructMember = value; }
    }

    // プロパティの "Size" クラス
    public SizeClass SizeClassProp{
        get{ return this.SizeClassMember; }
        set{ this.SizeClassMember = value; }
    }
}

わかりにくいかもしれないが、このクラスでは物体の大きさを記憶する Size というメンバを2種類の形で保持している。一方は構造体で、他方はクラスだ。どちらも、幅と高さを表す Width と Height というプロパティがある。さらに、それぞれ単純な getter/setter を持ったプロパティを用意している。

問題は、このクラスをインスタンス化して使ったとき、その下にあるメンバに代入できるかという点である。以下コードは、それぞれ方法で Size(Class/Struct) の下の Width プロパティに値を代入するものである。

public static void Main(){
    TestClass test = new TestClass();

    // メンバ変数の構造体にアクセス
    test.SizeStructMember.Height = 100;

    // プロパティの構造体にアクセス
    test.SizeStructProp.Height   = 100; // コンパイルエラー

    // メンバ変数のクラスにアクセス
    test.SizeClassMember.Height  = 100;

    // プロパティのクラスにアクセス
    test.SizeClassProp.Height    = 100;
}

構造体をプロパティにした場合だけ「変数ではないため、'TestComponent.TestClass.SizeStructProp' の戻り値を変更できません。」というエラーが出てコンパイルに失敗する。それ以外は問題なく成功する。一体何故そんな事が起きるのだろうか。

上記の例は見かけ上は単純に代入しているように見えるが、実際には Size の配下のメンバにアクセスするためにプロパティの get メソッドが呼び出されている。クラスならば参照渡しされるのでメンバの値を変えてもきちんと反映されるが、構造体はあくまで値渡しだ。get で一時的に取り出した値の配下のメンバを変えたところで、次の瞬間には捨てられてしまう。全く意味が無いというわけだ。

例文のように、プロパティにしなければとりあえず正常に動作する。しかしメンバ変数に直接アクセスさせるというのは危険だし、値の変更をオブジェクトに通知できないので実用性もほぼ皆無である。クラスにしてしまうか、あるいは = new SizeStruct(100, 100); などとして、構造体ごと代入するしかない。

このことには、どんな問題があるだろうか。物体の位置管理に使える System.Drawing.Position や System.Drawing.Rectangle、System.Drawing.Size など、使いやすい構造体をクラスのメンバにプロパティとして据えるができないのだ。いや、出来ないわけではないが、上記で述べたとおりに直接的に値を変更できないので、かえって使い勝手が悪くなってしまう。そんなことをするくらいなら、Top, Left, Width, Height などひとつひとつプロパティにしていったほうが数倍便利なのが本音である。

簡単に纏めてみた。

配下のメンバに代入可能か
構造体クラス
メンバ変数○可能○可能
プロパティ×エラー○可能

投稿者 : 20:54 | コメント (0) | トラックバック (0)

トラックバック

このエントリーのトラックバックURL:
http://totora.jpn.org/mt/mt-tb.cgi/126

コメント

コメントしてください




保存しますか?

(書式を変更するような一部のHTMLタグを使うことができます)