#contents

*概要 [#yca3bf43]
-''属性''とはクラス、メソッドなど、プログラムのさまざまな構成要素(エンティティ)に情報を付加するのに使う仕組みである。
-ソース上に記述可能。
-属性が示す情報は、リフレクションを利用して実行時に取得できる。
-定義済みの属性を使うことも、独自のカスタム属性を定義することもできる。
-属性を定義するとき、その名前には最後に''"Attribute"''を付ける慣例になっている。
--例:''DllImportAttribute,ConditionalAttribute''など
-ただしソース上で属性を使うときの記述では''"Attribute"''は省略できる(このことを知っておかないと''STAThread''をヘルプで引いてもSTAThreadAttributeしか出てこないので悩むことになる)
-属性はパラメータを持てる。
--名前付きパラメータとそうでないパラメータがあり、名前付きパラメータは省略可能。省略した場合は規定値が入力されたものとみなす。
-1 つの宣言で複数の属性を指定できる。その場合、個別に角かっこで囲むか、または同じ角かっこの中に入れる。
-一部の属性は、特定のエンティティに対して 2 回以上指定できる。~
例)
 [Conditional("DEBUG"), Conditional("TEST1")] 
 void TraceMethod() 
 {
   (略)
 }
-属性の定義はSystem.Attributeから派生した属性クラスを定義することで行う。つまり属性の実体はクラスによって実装されている。

*新しい属性を作る例 [#z04658b7]
 namespace AttrTst 
 {
 	//クラスと構造体にしか付けられない属性であることを明記
 	[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct)]
 	public class AuthorAttribute : Attribute
 	{
 		public AuthorAttribute(string name) 
 		{ 
 			this.name = name; version = 1.0; 
 		}
 		public double version;
 		string name;
 	}
 
 	[Author("カーネル",version=1.1)]
 	public class cTst 
 	{
 		static void Main() 
 		{
 		}
 	}
 }

*属性の取得 [#d92179ad]
属性の情報はリフレクションを使って取得する。
 using System;
 using c = System.Console; // alias
 namespace AttrTst 
 {
 	//クラスと構造体にしか付けられない属性であることを明記
 	[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct)]
 	public class AuthorAttribute : Attribute
 	{
 		public AuthorAttribute(string name) 
 		{ 
 			this.name = name; version = 1.0; 
 		}
 		double version;
 		public double Version 
 		{
 			set{version = value;}
 			get{return version;}
 		}
 		string name;
 		public string Name 
 		{
 			get{return name;}
 		}
 	}
 
 	[Author("カーネル",Version=1.1)]
 	public class cTst 
 	{
 		static void Main() 
 		{
 			PrintAuthorInfo(typeof(cTst));
 			c.ReadLine();
 		}
 		public static void PrintAuthorInfo(Type t) 
 		{
 			Console.WriteLine("Author information for {0}", t);
 			Attribute[] attrs = Attribute.GetCustomAttributes(t);
 			foreach(Attribute attr in attrs) 
 			{
 				if (attr is AuthorAttribute) 
 				{
 					AuthorAttribute a = (AuthorAttribute)attr;
 					c.WriteLine("   {0}, version {1:f}",a.Name, a.Version);
 				} 
 				else 
 				{
 					c.WriteLine(attr.ToString());
 				}
 			}
 		}
 	}
 }
実行結果
 Author information for AttrTst.cTst
   カーネル, version 1.10

GetCustomAttributesがコールされたタイミングでAuthorAttributeクラスが生成される。

*覚えておくと役立つかも知れない属性 [#zae80706]
**Conditional属性 [#n19f0c3e]
条件付でコンパイルするメソッドを定義できる。デバッグ時だけ呼ばれるメソッドとか。くわしくはヘルプ参照

**Obsolete属性 [#k2075e84]
定義のところで以下のように書いておくと
 [Obsolete("古いモジュールのために残してあるだけなのでできるだけ使わないように。")]
 public int a;
コンパイル時にワーニングが出るようになる。
 warning CS0618: 'AttrTst.cTst.a' は古い形式です : '古いモジュールのために残してあるだけなのでできるだけ使わないように。'

**StructLayout属性 [#x5afa824]
マネージ メモリ内のクラスまたは構造体のデータ フィールドの物理的なレイアウトを制御。~
Cで言うところの ''#pragma pack'' の代わりに使えそう。ただしクラスとか構造体単位。

 /* C言語だとこのようになる構造体を渡したい場合
 #define ALLOC_COUNT 128 
 typedef struct tagTIME_INFO_EX{ 
   int YYYY; 
   int MM; 
   int DD; 
   int hh; 
   int mm; 
   int ss; 
   char str[ALLOC_COUNT]; 
 } TIME_INFO_EX, *PTIME_INFO_EX;
 */
 
 // C#ではこう書く
 [StructLayout( LayoutKind.Sequential, Pack = 4 )] 
 public struct TIME_INFO_EX 
 { 
     public int YYYY; 
     public int MM; 
     public int DD; 
     public int hh; 
     public int mm; 
     public int ss; 
     [MarshalAs( UnmanagedType.ByValArray, SizeConst = 128 )]
     public char[] str;  // C++: char str[128];
 }
 
 //呼び出す側
 [DllImport( "myutil.dll", EntryPoint = "GetNowTimeStructEx" ) ] 
 public static extern int GetNowTimeStructEx( out TIME_INFO_EX timeinfoEx ); 
 
 TIME_INFO_EX timeinfoEx; 
 GetNowTimeStructEx( out timeinfoEx );

**DefaultEvent属性 [#e762cf6d]
-自作のコントロールをデザイナでダブルクリックしたときにコードと結びつくイベントを示す
 [DefaultEvent("Hoge")]
 public class MyControl : ..... {
   public event EventHandler Hoge;
 }

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS