第12章 インデクサとプロパティ:連載 改訂版 C#入門(3/4 ページ)
オブジェクトを配列のようにアクセス可能にする「インデクサ」と、get/setアクセサをシンプルに記述できる「プロパティ」は、C#の洗練された機能だ。
12-6 プロパティを使う
プロパティは、Visual Basicなどに存在していた機能なので、Visual Basicのベテランであれば、すぐに理解することができるだろう。
プロパティとは、クラスのメンバ変数であるかのようにアクセス可能でありながら、処理の内容を自分で記述できる機能である。インデクサが配列であるかのようにアクセスできる機能とすれば、プロパティはメンバー変数であるかのように記述できる手段を提供する機能である。実際にプロパティを記述したサンプル・ソースをList 12-7に示す。
1: using System;
2:
3: namespace Sample006
4: {
5: class Class2
6: {
7: private int number;
8: public string Order
9: {
10: get
11: {
12: switch( number )
13: {
14: case 1:
15: return "one";
16: case 2:
17: return "two";
18: case 3:
19: return "three";
20: default:
21: return "unknown";
22: }
23: }
24: set
25: {
26: switch( value )
27: {
28: case "one":
29: number = 1;
30: break;
31: case "two":
32: number = 2;
33: break;
34: case "three":
35: number = 3;
36: break;
37: default:
38: number = -1;
39: break;
40: }
41: }
42: }
43: }
44: class Class1
45: {
46: [STAThread]
47: static void Main(string[] args)
48: {
49: Class2 t = new Class2();
50: t.Order = "one";
51: Console.WriteLine( t.Order );
52: }
53: }
54: }
このプログラムを実行するとFig.12-7のようになる。
まず、プロパティの宣言は8行目で行われている。8行目の書式はインデクサの宣言と似ているが、名前はthisではなく、具体的に自分で付けた名前(ここではOrder)となる。インデクサは角括弧で表されるので、名前で区別することは意味がないが、プロパティは変数のふりをするので、変数同様、名前を付けて区別をする意味がある。
処理内容の記述方法は、インデクサと同じなので説明を繰り返さない。その代わり、List 12-7では、記憶する内容と読み書きする内容を差し替えるという処理を示している。このサンプル・ソースでは、文字列を読み書きするプロパティOrderを定義しているが、実際に保存される値は7行目で宣言されている整数型変数のnumberに収められる。50行目に記述されているように「one」という文字列を代入すると、24〜41行目のset処理が実行される。その中で、28行目の「case "one"」により、29行目が実行され、変数numberには1が書き込まれる。そして、51行目の「t.Order」は10〜23行目のget処理を呼び出し、14行目の「case 1:」により、15行目が処理され「one」という文字列が返される。その結果、画面にはoneという文字列が表示される。
あたかも、oneという文字列を、Class2のインスタンスが保持しているかのように見えるが、実際にはoneを数値の1に置き換えて保存しているのである。このように、内部で保持するデータ形式と、外部に見せるデータ形式が一致しないときに、そのギャップを埋めるのがプロパティの使い方の1つである。
このようなケースは、ソフトのチューンナップなどを行っているとしばしば発生する。データの内部表現を変えれば高速化できると分かったとき、プロパティを使えば、内部表現を変更しながら、外部に見せるインターフェイスは変更しない、ということが実現できるのである。
12-7 プロパティと+=演算子
+=演算子は、「a += b」としたときに、変数aにbを加え、変数aに戻すという機能を実現する。このとき、変数ではなくプロパティを使うとどうなるだろうか? つまり、クラスClass2にプロパティNumberがあるとき、これに+=演算子を使ったら何が起こるだろうか、ということである。実際に試したものをList 12-8に示す。
1: using System;
2:
3: namespace Sample007
4: {
5: class Class2
6: {
7: private int number;
8: public int Number
9: {
10: get
11: {
12: Console.WriteLine("property get called");
13: return number;
14: }
15: set
16: {
17: Console.WriteLine("property set called");
18: number = value;
19: }
20: }
21: }
22: class Class1
23: {
24: [STAThread]
25: static void Main(string[] args)
26: {
27: Class2 t = new Class2();
28: t.Number = 1;
29: t.Number += 2;
30: Console.WriteLine( t.Number );
31: }
32: }
33: }
このプログラムを実行するとFig.12-8のようになる。
List 12-8のクラスClass2のNumberプロパティは、ただ単に整数を変数numberに保存するという機能を提供する。ただし、getとsetの処理が呼び出されたことが分かるように、12行目と17行目に、メッセージ出力のコードを入れてある。
処理の内容を順番に見ていこう。まず、27行目でClass2のインスタンスが作成される。そして、28行目で値「1」がプロパティに代入され、17行目により「property set called」が出力される。次に、29行目が処理されるが、ここではNumberプロパティの読み出しと、書き込みの両方が発生している。その結果、get処理が呼ばれ、「property get called」が表示され、それに引き続き、set処理が呼ばれ、「property set called」が表示されている。つまり、getして2を足してsetしているということである。その結果、変数numberは、もともと1であったところに2が足されて3になる。そして、Fig.12-8の4行目の「property get called」は、30行目のプロパティNumberの参照によって表示されたものである。当然、3という足し算の結果が最後の行に表示される。
このように、+演算子と代入が有効に機能するデータ型のプロパティであれば、プロパティに+=演算子を使うことができる。-=など、ほかの演算子でも同じことがいえる。
Copyright© Digital Advantage Corp. All Rights Reserved.