連載

C#入門

第20回 実行時に参照可能な属性

(株)ピーデー
川俣 晶
2002/01/23


クラスに付く属性

 これまでの例は、すべてメソッドに付く属性であったが、もちろん、クラスや引数や戻り値などに付けることもできる。以下はクラスに付けてみた例である。メソッドではなく、クラスごとにプログラマの名前を記述するように変更してみた。

 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個しか記述できないので、繰り返し処理する意味はなかった。しかし、複数指定を許すと、複数のインスタンスを処理する場合があるため、繰り返す必要が出てくる。


 INDEX
  第20回 実行時に参照可能な属性
    1.属性(アトリビュート)とは何か?
  2.クラスに付く属性
    3.名前付き引数
    4.廃止予定を事前に告げるObsolete属性
    5.Webサービスで使われる属性
 
「C#入門」


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メールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間