連載

改訂版 プロフェッショナルVB.NETプログラミング

Chapter 14 属性

株式会社ピーデー 川俣 晶
2004/09/02
Page1 Page2 Page3 Page4


 本記事は、(株)技術評論社が発行する書籍『VB6プログラマーのための入門 Visual Basic .NET 独習講座』の一部分を許可を得て転載したものです。同書籍に関する詳しい情報については、本記事の最後に掲載しています。

 属性とは、クラス、メソッドなど、プログラミングに使用するさまざまな構成要素に付加できる情報といえる。属性の情報は、ソース・コード上に記述することが可能で、さまざまなプログラムからこの情報が参照できる。VB 6に限らず、これまでのプログラム言語ではあまり見かけない新しいタイプの機能だが、活用できるようになると効果は絶大である。固定長文字列など、一部の機能は、この属性を通じて指定することになるので、属性の使い方を把握しておこう。

属性とは何か?

 属性は、VB.NET独自の新しい機能である。同じ.NET Framework上で使用する言語であるC#などにも存在するが、その構文は異なっている。また、属性といっても、XMLでいう属性(attribute)とは異なる役割を持った機能となっている。オブジェクト指向より新しい「アスペクト指向」というプログラミング方法を意識した機能ともいわれる。

 では、具体的に属性とは何をするための機能なのか。属性とは、クラス、メソッドなど、プログラミングに使用するさまざまな構成要素に付加できる情報といえる。属性の情報はソース・コード上に記述することが可能で、さまざまなプログラムからこの情報が参照できる。

 それでは実際に属性が使われる例を見てみよう。ここでは、入出力時の文字列の長さを指定する役割を与えられている、VBFixedStringAttribute属性を使った例を見てみよう。VBFixedStringAttribute属性は、固定長文字列ランダム・ファイルとVBFixedString属性でも取り上げたが、属性としての側面は詳しく説明されていない。そこで、ランダム・ファイルとVBFixedString属性で紹介したサンプルソース(リスト3-27)を、もう一度取り上げて、属性に着目しながら解説してみよう。

 なお、エラーが発生しても確実にファイルが閉じるように、TryステートメントとFinallyブロックを追加する変更が加えてある。また、VBFixedStringAttributeをVBFixedStringと表記している場合もあるが、どちらも同じものを示す。この違いについては、属性の名前のバリエーションで解説している。

 1: Private Structure Person
 2:   Public Age As Integer
 3:   <VBFixedStringAttribute(32)> Public Name As String
 4: End Structure
 5:
 6: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 7:   Dim p As Person
 8:   FileOpen(1, "c:\test.dat", OpenMode.Random, , , Len(p))
 9:   Try
10:     p.Age = 17
11:     p.Name = "太郎"
12:     FilePut(1, p, 1)
13:     p.Age = 18
14:     p.Name = "花子"
15:     FilePut(1, p, 2)
16:
17:     FileGet(1, p, 1)
18:     Trace.WriteLine(p.Age)
19:     Trace.WriteLine(p.Name)
20:     FileGet(1, p, 2)
21:     Trace.WriteLine(p.Age)
22:     Trace.WriteLine(p.Name)
23:   Finally
24:     FileClose(1)
25:   End Try
26: End Sub
リスト14-1 文字列を固定長として扱うVBFixedStringAttribute属性を使用したプログラム

 これを実行すると以下のようになる。

1: 17
2: 太郎
3: 18
4: 花子
リスト14-2 リスト14-1の実行結果

 ここで、属性は3行目に使用されている<VBFixedStringAttribute(32)>という部分である。これは、その後に続くPublic Name As Stringというフィールドに付加情報を与えるために使用されている。属性はさまざまなものに付けられるが、この属性はフィールドに付く属性である。

 この属性は“VBFixedStringAttribute”が属性名となる。ほかにも多くの名前を持つ属性が存在し、属性を自作すればいくらでも種類は増える。“<”から“>”までの範囲が属性の記述であると見なされる。属性名のあとの“(”から“)”までが属性の引数を記述するために使われている。VBFixedStringAttributeの引数は1つだけ存在し、文字列の長さを指定する整数を指定する。

 この属性によって、フィールドで指定されたString型の振る舞いは変わらない。つまり、このNameフィールドの文字列が固定長文字列になるわけではない。指定した長さより短い文字列を代入することはできるし、それより長い文字列を代入することもできる。しかし、このプログラム全体として見ると、固定長フィールドを使ったランダム・アクセス・ファイルが実現されている。つまり、入出力の時点では、文字列は固定長として扱われているわけで、属性が効果を発揮していることになる。

 代入では効果を発揮しないが、入出力時には効果を発揮するとは、どういうことなのだろうか? それは、基本的に属性はプログラム言語レベルの動作に影響を与えず、その属性を参照するプログラムにのみ影響を与えるという特徴による。VBFixedStringAttribute属性は、主にFilePutメソッドやFileGetメソッドを用いて、固定長フィールドのランダム・アクセス・ファイルを構成するために使われることを意図して用意された属性である。そのため、FilePutメソッドやFileGetメソッドは、入出力時にVBFixedStringAttribute属性の値を調べ、それによって入出力するフィールドサイズを計算し、固定長として文字列を扱う。しかし、このような動作は、FilePutメソッドやFileGetメソッドがVBFixedStringAttributeを意識するように作成されていることで実現されるものであり、そうではない入出力関連メソッドを用いて入出力する際は、一切影響を与えることはない。

固定長配列を指定するVBFixedArrayAttribute属性

 前節では、VBFixedStringAttribute属性を取り上げて解説したが、これ1つでは物足りない。もう1つ、VBFixedStringAttribute属性と似た機能を実現する、VBFixedArrayAttribute属性も見てみよう。

 VBFixedStringAttribute属性は、固定長文字列を実現するために文字列の長さを指定するが、VBFixedArrayAttribute属性は配列のサイズを指定する。VB.NETにおいて、配列型は可変長であるという前提が置かれている。そのため、固定長の配列をフィールドで宣言することができない(ローカル変数としては宣言可能)。そこで、固定長レコードのランダム・アクセス・ファイルを実現するには、配列の長さを指定する機能が必要になる。VBFixedArrayAttribute属性は、それを行うためのものである。配列を含む構造体をランダム・アクセスするサンプル・プログラムを、リスト14-3のように記述してみた。

 1: Private Structure Sample
 2:   <VBFixedArrayAttribute(3)> Public Numbers() As Integer
 3: End Structure
 4:
 5: Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
 6:   Dim n As New Sample()
 7:   n.Numbers = New Integer(3) {}
 8:   FileOpen(1, "c:\test.dat", OpenMode.Random, , , Len(n))
 9:   Try
10:     Dim i As Integer
11:     For i = 0 To 3
12:       n.Numbers(i) = i
13:     Next
14:     FilePut(1, n, 1)
15:     For i = 0 To 3
16:       n.Numbers(i) = i + 4
17:     Next
18:     FilePut(1, n, 2)
19:
20:     FileGet(1, n, 1)
21:     For i = 0 To 3
22:       Trace.WriteLine(n.Numbers(i))
23:     Next
24:     FileGet(1, n, 2)
25:     For i = 0 To 3
26:       Trace.WriteLine(n.Numbers(i))
27:     Next
28:   Finally
29:     FileClose(1)
30:   End Try
31: End Sub
リスト14-3 固定長の配列を宣言するためのVBFixedArrayAttribute属性を使用したプログラム

 これを実行すると以下のようになる。

1: 0
2: 1
3: 2
4: 3
5: 4
6: 5
7: 6
8: 7
リスト14-4 リスト14-3の実行結果

 ここで注目すべき個所は、ソース2行目のVBFixedArrayAttribute属性である。Public Numbers() As Integerという配列宣言は可変長であり、長さは決まっていない。サイズを書き込むとビルド・エラーになる。しかし、VBFixedArrayAttribute属性が付加されたことにより、FilePutメソッドや、FileGetメソッドは、配列の大きさを正しく判定し、常に固定長でレコードを読み書きすることができる。

 もう1点、念のために説明すると、7行目は構造体内部の配列の初期化のために存在しているコードである。2行目で宣言されているNumbersは、配列への参照を入れる入れ物としてしか機能していない。そこで、本物の配列を作成して、それへの参照を入れてやる必要がある。“New Integer(3) {}”とは、要素4個のInteger型の配列を新規に作成することを意味する。最後の“{}”は省略できない。作成時に内容を初期化したいときは、{}の中に値を列挙することもできる。このようにして作成した配列をNumbersフィールドに代入することで、配列への参照が代入される(配列については、配列の初期化を参照)。

オブジェクトのシリアライズ

 オブジェクトを外部へ出力したり、外部から入力したりするために「シリアライズ」という機能が用意されることが多い。シリアライズはクラス・ライブラリが提供する機能であり、それ自体は特定の手法を示す言葉ではなく、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
リスト14-5 オブジェクトのシリアライズのためにSerializable属性を使用したプログラム

 これを実行すると以下のような結果になる。このサンプル・プログラムは、Personクラスの内容をファイル「c:\test.dat」に書き出してから、再度読み込んで内容を表示している。

1: 17
2: 山田太郎
3: False
リスト14-6 リスト14-5の実行結果

 このソースで最も注目すべき点は、10行目のクラス宣言に付加されたSerializable属性である。この属性が付加されていることにより、Personクラスはシリアライズできると判断される。では、だれがその判断を行うのかというと、22行目で使用されているBinaryFormatterクラスである。このクラスは、バイナリ形式でシリアライズを行う機能を持っている。25行目のように、このクラスのインスタンスのSerializeメソッドを使うことにより、シリアライズ可能なインスタンスの内容を指定ストリームに書き込むことができる。これにより、インスタンスの内容がファイルの中に記憶される。

 次に注目する価値があるのは、13行目のNonSerialized属性である。この属性は、クラスではなくフィールドに付く。そして、そのフィールドがシリアライズの対象ではないことを指定する。これにより、Public Flag As Booleanはシリアライズの対象から除外され、20行目で代入した値はファイルに保存されない。実行結果を見ると、Flagの値のみ代入した値が再現されていないことが分かるだろう。属性には、こういう指定に使う方法もある。

 さて、このほかに説明を要する点は33行目だろう。DeserializeメソッドはSerializeメソッドの逆、つまりSerializeメソッドで書き出されたデータからオブジェクトを作成する機能を持っている。DeserializeメソッドはObject型を返すため、元の型に戻すためにCType関数を使用している。


 INDEX
  [連載] 改訂版 プロフェッショナルVB.NETプログラミング
  Chapter 14 属性
  1.属性とは何か?/固定長配列を指定するVBFixedArray属性/オブジェクトのシリアライズ
    2.属性の名前のバリエーション/Declare文の引数型を変換するMarshalAs属性/条件付きメソッド
    3.属性を自作する/クラスに付く属性/複数の属性を持たせる
    4.名前付き引数/Webサービスで使われる属性の概要
 
「改訂版 プロフェッショナルVB.NETプログラミング 」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH