属性は、メタデータまたは宣言型情報をコード (アセンブリ、型、メソッド、プロパティなど) と関連付ける強力な方法を提供します。 属性をプログラム エンティティに関連付けた後は、リフレクション と呼ばれる手法を使用して、実行時に属性クエリを実行できます。
属性には、次のプロパティがあります。
- 属性は、プログラムにメタデータを追加します。 メタデータ は、プログラムで定義されている型に関する情報です。 すべての .NET アセンブリには、アセンブリで定義されている型と型メンバーを記述するメタデータの指定されたセットが含まれています。 カスタム属性を追加して、その他の必要な情報を指定できます。
- 属性は、アセンブリ全体、モジュール、またはクラスやプロパティなどの小さなプログラム要素に適用できます。
- 属性は、メソッドやプロパティと同じ方法で引数を受け取ることができます。
- 属性を使用すると、プログラムはリフレクションを使用して、他のプログラム内の独自のメタデータまたはメタデータを調べることができます。
リフレクションの操作
が提供するType API は、アセンブリ、モジュール、および型を記述します。 リフレクションを使用すると、型のインスタンスを動的に作成したり、型を既存のオブジェクトにバインドしたり、既存のオブジェクトから型を取得したり、メソッドを呼び出したり、そのフィールドとプロパティにアクセスしたりできます。 コードで属性を使用すると、リフレクションを使用してそれらにアクセスできます。 詳細については、「属性の」を参照してください。
GetType() メソッドを使用したリフレクションの簡単な例を次に示します。
Object
基底クラスのすべての型は、変数の型を取得するために使用されるこのメソッドを継承します。
手記
C# (using System;
) コード ファイルの先頭に using System.Reflection;
ステートメントと ステートメントを追加してください。
// Using GetType to obtain type information:
int i = 42;
Type type = i.GetType();
Console.WriteLine(type);
出力には、次の種類が表示されます。
System.Int32
次の例では、リフレクションを使用して、読み込まれたアセンブリの完全な名前を取得します。
// Using Reflection to get information of an Assembly:
Assembly info = typeof(int).Assembly;
Console.WriteLine(info);
出力は次の例のようになります。
System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
IL のキーワードの相違点
C# キーワード protected
と internal
は中間言語 (IL) では意味を持たず、リフレクション API では使用されません。 IL の対応する用語は、ファミリー とアセンブリ です。 これらの用語を使用する方法を次に示します。
- リフレクションを使用して
internal
メソッドを識別するには、IsAssembly プロパティを使用します。 -
protected internal
メソッドを識別するには、IsFamilyOrAssemblyを使用します。
属性の操作
属性はほぼすべての宣言に配置できますが、特定の属性によって有効な宣言の型が制限される場合があります。 C# では、属性の名前を角かっこ ([]
) で囲んで、適用するエンティティの宣言の上に配置することで、属性を指定します。
この例では、SerializableAttribute 属性を使用して、クラスに特定の特性を適用します。
[Serializable]
public class SampleClass
{
// Objects of this type can be serialized.
}
DllImportAttribute 属性を使用してメソッドを宣言できます。
[System.Runtime.InteropServices.DllImport("user32.dll")]
extern static void SampleMethod();
宣言には複数の属性を配置できます。
void MethodA([In][Out] ref double x) { }
void MethodB([Out][In] ref double x) { }
void MethodC([In, Out] ref double x) { }
一部の属性は、特定のエンティティに対して複数回指定できます。 次の例は、ConditionalAttribute 属性のマルチユースを示しています。
[Conditional("DEBUG"), Conditional("TEST1")]
void TraceMethod()
{
// ...
}
手記
慣例により、すべての属性名はサフィックス "Attribute" で終わり、.NET ライブラリ内の他の型と区別されます。 ただし、コードで属性を使用する場合は、属性サフィックスを指定する必要はありません。 たとえば、[DllImport]
宣言は [DllImportAttribute]
宣言と同じですが、DllImportAttribute
は .NET クラス ライブラリ内のクラスの実際の名前です。
属性パラメーター
属性の多くは、位置指定パラメーター、名前のないパラメーター、または名前付きパラメーターを持っています。 次の表では、名前付き属性と位置指定属性を操作する方法について説明します。
位置指定パラメーター
属性コンストラクターのパラメーター:
名前付きパラメーター
属性のプロパティまたはフィールド:
- 指定する必要があります。省略できません
- 常に最初に指定する
- 特定の順序で指定する
- 常に省略可能、false の場合は省略
- 位置指定パラメーターの後に指定する
- 任意の順序で指定する
たとえば、次のコードは、3 つの同等の DllImport
属性を示しています。
[DllImport("user32.dll")]
[DllImport("user32.dll", SetLastError=false, ExactSpelling=false)]
[DllImport("user32.dll", ExactSpelling=false, SetLastError=false)]
最初のパラメーターである DLL 名は位置指定であり、常に先頭になります。 他のインスタンスは名前付きパラメーターです。 このシナリオでは、両方の名前付きパラメーターの既定値は false であるため、省略できます。 既定のパラメーター値については、個々の属性のドキュメントを参照してください。 許可されるパラメーター型の詳細については、C# 言語仕様の「属性」セクションを参照してください。
属性の対象
属性の ターゲット は、属性が適用されるエンティティです。 たとえば、属性は、クラス、メソッド、またはアセンブリに適用できます。 既定では、属性はそれに続く要素に適用されます。 ただし、関連付ける要素 (メソッド、パラメーター、戻り値など) を明示的に識別することもできます。
属性ターゲットを明示的に識別するには、次の構文を使用します。
[target : attribute-list]
次の表に、使用可能な target
値の一覧を示します。
ターゲット値 | 適用対象 |
---|---|
assembly |
アセンブリ全体 |
module |
現在のアセンブリ モジュール |
field |
クラスまたは構造体のフィールド |
event |
出来事 |
method |
メソッドまたは get および set プロパティ アクセサー |
param |
メソッド パラメーターまたは set プロパティ アクセサー パラメーター |
property |
財産 |
return |
メソッド、プロパティ インデクサー、または get プロパティ アクセサーの戻り値 |
type |
構造体、クラス、インターフェイス、列挙型、またはデリゲート |
field
ターゲット値を指定して、自動的に実装されるプロパティ用に作成されたバッキング フィールドに属性を適用できます。
次の例は、アセンブリとモジュールに属性を適用する方法を示しています。 詳細については、「共通属性 (C#)」を参照してください。
using System;
using System.Reflection;
[assembly: AssemblyTitleAttribute("Production assembly 4")]
[module: CLSCompliant(true)]
次の例は、C# のメソッド、メソッド パラメーター、およびメソッドの戻り値に属性を適用する方法を示しています。
// default: applies to method
[ValidatedContract]
int Method1() { return 0; }
// applies to method
[method: ValidatedContract]
int Method2() { return 0; }
// applies to parameter
int Method3([ValidatedContract] string contract) { return 0; }
// applies to return value
[return: ValidatedContract]
int Method4() { return 0; }
手記
ValidatedContract
属性が有効であると定義されているターゲットに関係なく、return
属性が戻り値にのみ適用されるように定義されている場合でも、ValidatedContract
ターゲットを指定する必要があります。 つまり、コンパイラは、あいまいな属性ターゲットを解決するために AttributeUsage
情報を使用しません。 詳細については、「AttributeUsage」を参照してください。
属性の使用方法を確認する
コードで属性を使用する一般的な方法を次に示します。
-
HttpPost
属性を使用して、POST メッセージに応答するコントローラー メソッドをマークします。 詳細については、HttpPostAttribute クラスを参照してください。 - ネイティブ コードと相互運用するときにメソッド パラメーターをマーシャリングする方法について説明します。 詳細については、MarshalAsAttribute クラスを参照してください。
- クラス、メソッド、インターフェイスのコンポーネント オブジェクト モデル (COM) プロパティについて説明します。
- DllImportAttribute クラスを使用してアンマネージ コードを呼び出します。
- タイトル、バージョン、説明、または商標の観点からアセンブリを記述します。
- 永続化のためにシリアル化するクラスのメンバーについて説明します。
- XML シリアル化のためにクラス メンバーと XML ノードの間でマップする方法について説明します。
- メソッドのセキュリティ要件について説明します。
- セキュリティを適用するために使用する特性を指定します。
- Just-In-Time (JIT) コンパイラを使用して最適化を制御し、コードをデバッグしやすくします。
- メソッドの呼び出し元に関する情報を取得します。
リフレクション シナリオを確認する
リフレクションは、次のシナリオで役立ちます。
- プログラムのメタデータ内の属性にアクセスします。 詳細については、「属性に格納されている情報の取得」を参照してください。
- アセンブリ内の型を調べてインスタンス化します。
- System.Reflection.Emit 名前空間のクラスを使用して、実行時に新しい型をビルドします。
- 実行時に作成された型に対して遅延バインディングとアクセス メソッドを実行します。 詳細については、「動的に読み込み、型を使用する」を参照してください。
関連リンク
- 一般属性 (C#)
- 呼び出し元情報 (C#)
- 属性
- リフレクション
- 型情報を表示する
- リフレクション型とジェネリック型
- System.Reflection.Emit
- 属性 に格納されている情報を取得する
.NET