クラスに付く属性
これまでの例は、すべてメソッドに付く属性であったが、もちろん、クラスや引数や戻り値などに付けることもできる。以下はクラスに付けてみた例である。メソッドではなく、クラスごとにプログラマの名前を記述するように変更してみた。
1: using System;
2: using System.Reflection;
3:
4: namespace ConsoleApplication17
5: {
6: [AttributeUsage(AttributeTargets.Class)]
7: class AuthorAttribute : Attribute
8: {
9: private string _name;
10: public AuthorAttribute( string name )
11: {
12: _name = name;
13: }
14: public string name
15: {
16: get { return _name; }
17: }
18: }
19: [Author("Ichiro")]
20: class Sample1
21: {
22: }
23: [Author("Jiro")]
24: class Sample2
25: {
26: }
27: [Author("Saburo")]
28: class Class1
29: {
30: public static void dumpAuthor( string className )
31: {
32: Type type = Type.GetType("ConsoleApplication17." + className);
33: object [] list = type.GetCustomAttributes(typeof(AuthorAttribute),false);
34: foreach( AuthorAttribute item in list )
35: {
36: Console.WriteLine( "class {0} is written by {1}", className, item.name );
37: }
38: }
39: static void Main(string[] args)
40: {
41: dumpAuthor( "Sample1" );
42: dumpAuthor( "Sample2" );
43: dumpAuthor( "Class1" );
44: }
45: }
46: } |
|
クラスに付く属性を定義したサンプル・プログラム3 |
クラスごとにプログラマの名前を記述することができる。 |
これを実行すると以下のようになる。
|
サンプル・プログラム3の実行結果 |
クラス名とクラスに付けたAuthor属性の引数が表示される。
|
このソースのポイントは、6行目のAttributeUsage属性の引数をAttributeTargets.MethodからAttributeTargets.Classへ変更したことである。これにより、メソッドではなく、クラスに付く属性に機能が変化したのである。その結果、19、23、27行目の属性は、それぞれ、メソッドではなく、クラスの先頭に付くようになっている。
さて、もう1つのポイントは、リフレクションの機能によりクラスに属する属性を取得する方法である。32〜33行目を見ていただくと分かると思うが、それほど複雑なものではない。System.TypeクラスのstaticなメソッドであるGetTypeメソッドにクラス名を渡せば、そのクラスに関する情報を持つSystem.Type型のインスタンスが得られる。それにGetCustomAttributesメソッドが含まれるので、そのメソッドを呼び出せば属性の情報が得られる。後の処理はメソッドの場合と同じである。ただし注意が必要なのは、GetTypeメソッドを呼び出す場合は、ネームスペースを含むクラスのフルネームを指定しなければならないことである。他の例ではコンパイル時にクラスが確定されているが、GetTypeメソッドは実行時にクラスを検索して処理する都合によるものだ。
複数の属性を持たせる
上記の例では、クラスを記述したプログラマの名前をソースコードに埋め込めるようにしているが、実用上は難点が1つある。それは、クラスは常に1人で記述するとは限らないのに対し、名前は1つしか書けないことだ。これに対処するには、同じ属性を複数指定可能にすればよい。実際に、それを記述してみた例が以下である。
1: using System;
2: using System.Reflection;
3:
4: namespace ConsoleApplication18
5: {
6: [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
7: class AuthorAttribute : Attribute
8: {
9: private string _name;
10: public AuthorAttribute( string name )
11: {
12: _name = name;
13: }
14: public string name
15: {
16: get { return _name; }
17: }
18: }
19: [Author("Ichiro")]
20: class Sample1
21: {
22: }
23: [Author("Jiro"), Author("Saburo")]
24: class Sample2
25: {
26: }
27: [Author("Saburo")]
28: class Class1
29: {
30: public static void dumpAuthor( string className )
31: {
32: Type type = Type.GetType("ConsoleApplication18." + className);
33: object [] list = type.GetCustomAttributes(typeof(AuthorAttribute),false);
34: Console.WriteLine( "class {0} is written by {1} member(s)", className, list.Length );
35: foreach( AuthorAttribute item in list )
36: {
37: Console.WriteLine( " class {0} is written by {1}", className, item.name );
38: }
39: }
40: static void Main(string[] args)
41: {
42: dumpAuthor( "Sample1" );
43: dumpAuthor( "Sample2" );
44: dumpAuthor( "Class1" );
45: }
46: }
47: } |
|
複数の属性を指定したサンプル・プログラム4 |
1つのクラスに、カンマで区切った複数のAuthor属性を付けている。 |
これを実行すると以下のようになる。
|
サンプル・プログラム4の実行結果 |
クラスを記述したプログラマの名前に加えてその人数も表示している。
|
ここで注目すべきは23行目である。カンマで区切って、Author属性が2回連続して記述されている。これにより、クラスSample2には、2つのAuthor属性が付加される。
これを許すために、6行目のAttributeUsage属性の引数に、「AllowMultiple = true」という指定が追加されている。AllowMultipleは同じ属性を複数書いてよかどうかを指定するプロパティで、trueなら複数を許すことを示す。指定しなければfalseが指定されたものと見なされる。
さて、重要なことではないが、このサンプル・ソースになって、35〜38行目のforeachループに、繰り返す意義が初めて生まれたことになる。これまでの例は、同じ名前の属性は1個しか記述できないので、繰り返し処理する意味はなかった。しかし、複数指定を許すと、複数のインスタンスを処理する場合があるため、繰り返す必要が出てくる。
Insider.NET 記事ランキング
本日
月間