VB6.0の頃は、デフォルトプロパティというものがあって、
http://akihitoyamashiro.com/VBA/CreateDefaultProperty.htm
なところにあるように、「Attribute Value.VB_UserMemId = 0 」という属性(みたいなもの)を設定して、オブジェクトのプロパティを決めていました。まあ、大ざっぱに言えば、「obj.Item(10)」のように配列にアクセスするときに、「obj(10)」のように、Itemメソッドを省略できるという技です。普通は Item というメソッドが使われるのですが、このメソッド名は「Attribute Value.VB_UserMemId = 0 」を付けメソッド(プロパティ)の場合は、これが省略できるという仕組みです。
で、これを C#, VB ならばどうやるか、という話を少し。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | private void button1_Click( object sender, EventArgs e) { DefaultClass obj = new DefaultClass(); Debug.Print(obj[10]); Debug.Print(obj.Item(10)); Debug.Print(obj[ "key" ]); Debug.Print(obj.Item( "key" )); } private void button2_Click( object sender, EventArgs e) { DefaultClass obj = new DefaultClass(); // string 型に暗黙の変換 string name = obj; Debug.Print( "name:{0}" , name); // int 型に暗黙の変換 int num = obj; Debug.Print( "num:{0}" , num); } |
「既定のプロパティ」という機能をちょっと拡大解釈して、添え字(あるいは添え文字列?)で扱う時のメソッドと、単純にオブジェクトから別の型に変換されるときのプロパティ、という風に分けてみました。
■添え字を使う場合
「obj.Item[10]」と「obj(10)」が同じような動作をするためには、次なように、this[…] のように書きます。[] 演算子は多重定義が効くので、int型とstring型の両方を一度に作れます。配列風なものと連想配列風なものですね。これは、string型だけじゃなくて、任意のobject型も使えるので結構不思議な使い方ができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public string Item( int i) { return string .Format( "item-int:{0}" , i); } public string Item( string name) { return string .Format( "item-str:{0}" , name); } // Default と同じ扱いが可能 public string this [ int i] { get { return this .Item(i); } } // 連想配列風に public string this [ string name] { get { return this .Item(name); } } |
ちなみに、[] 演算子は、ふたつ以上の引数を持つことができるので、obj[x,y] のようなアクセスの仕方もできます。定義は↓のようですね。
1 2 3 4 5 | // 引数が二つある場合 public string this [ int x, int y] { get { return string .Format( "{0} {1}" , x, y); } } |
■暗黙の変換を使う
もうひとつ、implicit を使って暗黙的に変換させることができます。普通は、自前で作成したクラスからstring型のプロパティを取り出すには、ToString メソッドをオーバーライドしたりしますが、もっと端的にキャストを使っても良いわけです。↓のように、DefaultClass 型から、string型やint型に自動で変換してくれます。
1 2 3 4 5 6 7 8 9 10 | rivate void button2_Click( object sender, EventArgs e) { DefaultClass obj = new DefaultClass(); // string 型に暗黙の変換 string name = obj; Debug.Print( "name:{0}" , name); // int 型に暗黙の変換 int num = obj; Debug.Print( "num:{0}" , num); } |
これを実装するためには、implicit を使って、string型や int型に自動的に変換されるようにします。ちなみに、implicit は暗黙変換なので、明示的な変換(キャスト)を使いたい場合は、explicit を使えば ok です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public string ItemName { get ; set ; } public int ItemNum { get ; set ; } /// <summary> /// 暗黙変換(string型) /// </summary> /// <param name="obj"></param> /// <returns></returns> public static implicit operator string ( DefaultClass obj ) { return obj.ItemName; } /// <summary> /// 暗黙変換(int型) /// </summary> /// <param name="obj"></param> /// <returns></returns> public static implicit operator int (DefaultClass obj) { return obj.ItemNum; } |
これが何に役に立つかというと…あまりにトリッキー過ぎて役に立たないというか、文法的に不思議な感じになってしまというか、妙な感じになるので、多用するのはちょっと、という気になります。
…が、いま作っている ExDoc という XML をパースするライブラリは、このあたりを使っていて配列をstring型に自動変換したり、コレクションから単一のオブジェクトに代入するときに暗黙にキャストをしていたりします、という詳細は別の機会に。ソースコードは git にあるので、moonmile/ExDoc – GitHub ご覧ください。ただ今、HTML のパースを準備中。
ピンバック: .NET Clips