ReflectorでのGetCustomAttributesの呼び出し例に続いて、コードの管理対象部分(つまり、ランタイムに移行して外部呼び出しになるポイント)がCustomAttribute.GetCustomAttributesでダウンします。
この時点で、メソッドは、属性がロードされているオブジェクトを取り巻くメタデータのバイトを調べています。
そこには、呼び出されているランタイムコンストラクターを見つけるためにさらにリフレクションを行うコードがあります。例えば
[MyAttribute]
デフォルトを呼び出しますが、
[MyAttribute(1, "hello", typeof(T))]
をとるコンストラクターを呼び出すことになります(Int, String, Type)
。
インスタンスのキャッシュが実行されているという証拠はそこにはありません。つまり、属性インスタンスは、反映されたときにオンデマンドで作成されます。
証拠
前述のマネージドランタイム遷移は、CustomAttribute._CreateCaObjectで発生します。このメソッドが実際に作成したインスタンスをキャッシュするかどうかを静的に分析するのは簡単ではありませんが(おそらく、属性宣言が存在するメタデータ内の場所を示すメモリバッファーポインターの形式で十分な状態情報を取得する可能性があります)、事実:
- コンストラクターは常に呼び出され、
- 新しいコンストラクターパラメーターは常に読み取られ、フィードされます。
これは、属性が常に構築されていることを示しています。
もちろん、テストでコードを記述することで、これをテストできます。
[TestMethod]
public void TestMethod1()
{
//if running in MSTest you have to allow for the test runner to reflect
//over the class as it looks for the TestClass attribute - therefore if our
//assumption is correct that a new instance is always constructed when
//reflecting, our counter check should start at 2, not 1.
Type t = typeof(AttributeTest);
var attributes =
t.GetCustomAttributes(typeof(AttributeTest.TheAttributeAttribute), false);
//check counter
Assert.AreEqual(2, AttributeTest.TheAttributeAttribute.Counter);
var attributes2 =
t.GetCustomAttributes(typeof(AttributeTest.TheAttributeAttribute), false);
//should be one louder (sorry, 'one bigger' - the Spinal Tap influence :) )
Assert.AreEqual(3, AttributeTest.TheAttributeAttribute.Counter);
}
[TheAttribute]
public class AttributeTest
{
public class TheAttributeAttribute : Attribute
{
static int _counter = 0;
public static int Counter { get { return _counter; } }
public TheAttributeAttribute()
{
_counter++;
Console.WriteLine("New");
}
}
}
したがって、メタデータ属性を効率的に使用するには、属性をユーザーコードにキャッシュする必要があります。ただし、属性が何らかの方法で変更可能であるために、特定T
のインスタンスまたはすべての「インスタンス」に適用できない場合を除きます(もちろん、引用符で囲みます。メソッドはm
、タイプのインスタンスのメソッドの1回だけメモリに保存されますT
)。
したがって、これに続いて、コード内の属性へのすべての参照がnullになると、GCで属性を使用できるようになります。その属性のすべてのメンバーにも同じことが当てはまります。
したがって、GetCustomAttributes()を使用して属性を取得し、それを使用してから参照を破棄するメソッドは、GCが必要なときにクリーンアップするために、その属性の新しいインスタンスをリリースしました。
したがって、-属性インスタンスは、すべてのクラスインスタンスとまったく同じメモリ管理およびライフタイムルールによって管理されます。したがって、@ PieterGが彼の答えで言っていることは正しいです。つまり、その属性へのすべての参照が解放された後、いつでもデストラクタを呼び出すことができます。