連載プロフェッショナルVB.NETプログラミング
|
属性を自作する
前回では、.NET Frameworkが提供する属性ばかりを紹介したが、属性はシステムがあらかじめ用意したものに限らない。一般のプログラマーが自分で新しい属性を定義して使用することもできる。例として、メソッドを記述したプログラマーの名前をソース・コード中に挿入するための属性を作成してみよう。
|
|
メソッドにプログラマーの名前を付加するためのAuthor属性を記述したサンプル・プログラム1 |
これを実行すると以下のようになる。
|
|
サンプル・プログラム1の実行結果 |
さて、肝心の中身だが、これには説明することが多くあるので、心して読んでいただきたい。
まず、属性本体の定義を見てみよう。属性は一種のクラスであると説明したとおり、クラスとして定義する。1〜12行目で定義されているクラスが、自作属性ということになる。しかし、ただ単にクラスを記述するだけでは属性にならない。3つの追加作業を行わねばならない。1つ目は、2行目に記述したようにAttributeクラス(System.Attributeクラス)を継承することである。2つ目は、クラスの名前をAttributeという文字列で終わるようにすることである。この文字列は、すでに述べたとおり、属性として記述する際には省略可能である。3つ目は、1行目に見られるようなAttributeUsage属性を付加して、それが何に付く属性であるかを示すことである。ここでは、AttributeTargets.Methodが指定されているが、これはメソッドに付く属性であることを意味する。AttributeTargetsは列挙型で、ほかにもクラスなどのバリエーションが定義されている。必要なものを選んで指定すればよい。Or演算子で区切って、
[AttributeUsage(AttributeTargets.Method Or AttributeTargets.Class)]
というように複数を並べて指定することもできる。こうするとメソッドにもクラスにも付けられる属性になる。
これで新しい属性を誕生させることができた。これ以後、例えば14行目の<Author("Ichiro")>のように、メソッドの宣言の前に、この属性を記述することが可能となる。Authorという名前は、もちろん、AuthorAttributeというクラス名から、Attributeという文字列を省略した名前である。属性には、1つの文字列が引数として指定されているが、これは4〜6行目のコンストラクタの引数がそのまま使われた結果である。つまり、4行目に記述された引数ByVal name As Stringに対応するものが、"Ichiro"という文字列である。
さて、ここでもう1つ考えねばならないことがある。属性を自作し、それをメソッドなどに付け加えることは簡単だが、それだけでは何の効果も発揮しないということである。例えば、VBFixedStringAttribute属性が効果を発揮するためには、VBFixedStringAttribute属性の情報を活用するFilePutメソッドやFileGetメソッドが不可欠である。それと同じように、自作属性を活用するには、それを活用するためにコードを記述する必要がある。このサンプル・プログラムでは、20〜27行目のDumpAuthorメソッドがそれに当たる。
DumpAuthorメソッドの中では、「リフレクション」という機能が使用されている。これは、プログラムそのものに対する情報にアクセスする機能である。例えば、あるクラスにどんな名前のメソッドが存在するかを実行中に調べることができる。クラスやメソッドの情報を調べる際に、それに付随する属性の情報も調べることができる。リフレクションはクラス・ライブラリの興味深い機能の1つであって、必ずしもVB.NET専用の機能というわけではないので、この連載では取り上げない。しかし、このサンプル・プログラムを読むために必要な知識をここで解説しておこう。
まず21行目を見ていただきたい。System.Reflection.MethodInfoクラスは、メソッドに関する情報を保持するクラスである。その中には、メソッドの名前や、属性などの情報が含まれる。この情報を取り出すために、Me.GetType().GetMethod(methodName)という式を計算している。Meはこの場合、現在処理中のフォームのインスタンスを示している。これにGetTypeメソッドを呼び出すことで、そのデータ型(Form1クラス)についての情報を持つSystem.Typeクラスのインスタンスを取得できる。さらに、そのインスタンスのGetMethodメソッドを呼び出すことで、引数で指定した名前のPublicなメソッドに関する情報が取得できるわけである。
次に22行目を見ていただきたい。21行目で取得したメソッド情報に対して、GetCustomAttributesメソッドを呼び出している。これが自作属性の情報を得るために使用できるメソッドである。第1引数に取得したい属性を表すクラスに対応するSystem.Type型の値を渡している。ある型に対するSystem.Type型の値は、GetType演算子で得ることができる。第2引数は、属性クラスが継承されたクラスかどうかを指定するものだが、ここでは継承関係が絡み合うような使い方はしていないので、シンプルにfalse(継承されていない)を指定している。
GetCustomAttributesメソッドの戻り値はObject型の配列だが、内容はもちろん、AuthorAttribute型の配列である。とはいえ、AuthorAttribute属性は1つのメソッドに複数付けることを許可する指定を入れていないので、配列といっても、通常は要素数1の配列になることが予想される。AuthorAttribute型の配列が得られれば、後は通常のプログラミングで対応できる範囲である。AuthorAttributeクラスのnameプロパティを経由してAuthor名を取り出して出力している。
クラスに付く属性
上の例はメソッドに付く属性であったが、クラスに付く属性も記述してみよう。
|
|
クラスに対して指定するAuthor属性を記述したサンプル・プログラム2 | |
(このコードが含まれるプロジェクトの名前は「Sample006n」) |
これを実行すると以下のようになる。
|
|
サンプル・プログラム2の実行結果 |
まず、14行目や17行目で、Test1やTest2などのクラスにAuthor属性が付いていることが分かると思う。クラスに付加する属性を宣言するには、1行目にあるように、AttributeUsage属性に、AttributeTargets.Methodではなく、AttributeTargets.Classという値を指定する必要がある。
クラスに付く属性に関する情報を得るために、ここではType(System.Type)クラスのGetTypeメソッドを使っている。これは指定された名前のクラスに関するTypeクラスのインスタンスを返すSharedなメソッドである。このメソッドの引数には、クラスのフルネームを指定する必要があるので、プロジェクト名の文字列("Sample006n.")を連結してフルネームとしている。もし、違うプロジェクト名でプロジェクトを作成した場合、この文字列も修正しなければ正常に動作しない。
クラスに関する情報を持つTypeクラスのインスタンスが得られたら、それに対してGetCustomAttributesメソッドを呼び出せば、カスタム属性の情報を取り出すことができる。このあたりは、メソッドの場合(サンプル・プログラム1)と同じである。
INDEX | ||
連載 プロフェッショナルVB.NETプログラミング | ||
第29回 属性(後編) | ||
1.属性を自作する | ||
2.複数の属性を持たせる | ||
3.Webサービスで使われる属性の概要 | ||
「プロフェッショナルVB.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用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|