連載
プロフェッショナルVB.NETプログラミング
第28回 属性(前編)
(株)ピーデー
川俣 晶
2002/12/07
|
|
オブジェクトのシリアライズ
オブジェクトを外部へ出力するために「シリアライズ」という機能が用意されることが多い。シリアライズは、特定の機能を示す言葉ではなく、世の中には、さまざまな方法でシリアライズを行うライブラリが存在する。VB.NETでは、あるクラスがシリアライズ可能であることを示すために、属性を用いて指定する方法が取られている。シリアライズはクラス・ライブラリが提供する機能であり、VB.NET独自の機能というわけではない。そのため、本連載では大きく取り上げないが、属性の利用例として属性がどのように使われているかを見てみよう。以下のようなサンプル・プログラムを用意してみた。
1: Imports System.IO
2: Imports System.Runtime.Serialization
3: Imports System.Runtime.Serialization.Formatters.Binary
4:
5: Public Class Form1
6: Inherits System.Windows.Forms.Form
7:
8: …Windows フォーム デザイナで生成されたコード…
9:
10: <Serializable()> Private Class Person
11: Public Age As Integer
12: Public Name As String
13: <NonSerialized()> Public Flag As Boolean
14: End Class
15:
16: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
17: Dim p1 As New Person()
18: p1.Age = 17
19: p1.Name = "山田太郎"
20: p1.Flag = True
21:
22: Dim formatter As New BinaryFormatter()
23: Dim outputStream As New FileStream("c:\test.dat", FileMode.Create)
24: Try
25: formatter.Serialize(outputStream, p1)
26: Finally
27: outputStream.Close()
28: End Try
29:
30: Dim p2 As Person
31: Dim inputStream As New FileStream("c:\test.dat", FileMode.Open)
32: Try
33: p2 = CType(formatter.Deserialize(inputStream), Person)
34: Finally
35: inputStream.Close()
36: End Try
37:
38: Trace.WriteLine(p2.Age)
39: Trace.WriteLine(p2.Name)
40: Trace.WriteLine(p2.Flag)
41: End Sub
42: End Class
|
|
オブジェクトのシリアライズのためにSerializable属性を使用したサンプル・プログラム3 |
これを実行すると以下のような結果になる。
このソースで最も注目すべき点は、10行目のクラス宣言に付加されたSerializable属性である。この属性が付加されていることにより、Personクラスはシリアライズできると判断される。では、だれがその判断を行うのかというと、22行目で使用されているBinaryFormatterクラスである。このクラスは、バイナリ形式でシリアライズを行う機能を持っている。25行目のように、このクラスのインスタンスのSerializeメソッドを使うことにより、シリアライズ可能なインスタンスの内容を指定ストリームに書き込むことができる。これにより、インスタンスの内容がファイルの中に記憶される。
次に注目する価値があるのは、13行目のNonSerialized属性である。この属性は、クラスではなくフィールドに付く。そして、そのフィールドがシリアライズの対象ではないことを指定する。これにより、Public Flag As Booleanはシリアライズの対象から除外され、20行目で代入した値はファイルに保存されない。実行結果を見ると、Flagの値のみ代入した値が再現されていないことが分かるだろう。属性には、こういう指定に使う方法もある。
さて、このほかに説明を要する点は33行目だろう。DeserializeメソッドはSerializeメソッドの逆、つまりSerializeメソッドで書き出されたデータからオブジェクトを作成する機能を持っている。DeserializeメソッドはObject型を返すため、元の型に戻すためにCType関数を使用している。
属性の名前のバリエーション
ここまでの説明を読んで、「あれ?」と思った読者もいるのではないだろうか。というのは、VBFixedStringAttribute属性を、VBFixedString属性と記述している資料も存在するからである。さらに、名前空間を明示した名前を記述しても、エラーにならない。以下のサンプル・プログラムは、Serializableを例にして、これらのバリエーションを並べて書いてみたものである。
1: <Serializable()> Private Class Sample1
2: Public a As Integer
3: Public b As Integer
4: End Class
5:
6: <SerializableAttribute()> Private Class Sample2
7: Public a As Integer
8: Public b As Integer
9: End Class
10:
11: <System.SerializableAttribute()> Private Class Sample3
12: Public a As Integer
13: Public b As Integer
14: End Class
|
|
属性を記述する場合の3つバリエーション |
このサンプル・プログラムで示した3つのクラスは、まったく同じ内容を定義していることになる。これらのクラスに付いた属性名、Serializable、SerializableAttribute、System.SerializableAttributeは、すべて同じものを示している。これは2つの事実を知ることで容易に理解することができる。
第1の事実は、属性の実体はクラスであるということだ。そのため、記述方法もクラスと何ら変わることはなく、System.SerializableAttributeとフルネームで書いてもよく、省略可能な名前空間名を省略して、SerializableAttributeと書いてもよい。また、Imports文でデフォルトの名前空間名を指定すれば、属性の名前空間名の部分を省略して書くこともできる。属性の機能について調べたいときも、クラス・ライブラリのリファレンスを開き、クラス名として属性名を調べることで、必要な情報を得ることができる。
第2の事実は、属性を実現しているクラスの名前は、必ずAttributeという文字列で終わり、この文字列は属性としてソース・コードに記述する際に省略可能ということである。つまり、SerializableAttributeという属性名を記述する際、最後の“Attribute”を省略して、Serializableとだけ書いてもよいということである。この機能により、VBFixedStringAttributeとVBFixedStringはどちらの名前を使っても結果は同じである。また、リファレンス・マニュアルを引くときに、VBFixedStringというキーワードでは出てこない場合があったとしても、それに省略された文字列Attributeを補い、VBFixedStringAttributeというキーワードで引いてみるというテクニックも可能である。しかし、この省略は属性として記述する場合にのみ有効なものであり、クラス名として記述する場合はAttributeという文字列を省略できない。
なお、リファレンス・マニュアルで、VBFixedStringAttributeを引いても、これが属する名前空間が明記されていないが、オブジェクト・ブラウザで見ればすぐに分かる。VBFixedStringAttribute属性の名前空間は、Microsoft.Visual Basicである。つまり、そのフルネームは、Microsoft.Visual Basic.VBFixedStringAttributeとなる。
|
オブジェクト・ブラウザで表示させたVBFixedStringAttribute属性(VBFixedStringAttributeクラス) |
Insider.NET 記事ランキング
本日
月間