.NET属性:GetCustomAttributes()が毎回新しい属性インスタンスを作成するのはなぜですか?
-
03-07-2019 - |
質問
だから私は.NETの属性でもう少し遊んでいて、Type.GetCustomAttributes()を呼び出すたびに属性の新しいインスタンスが作成されることに気付きました。何故ですか?属性インスタンスは基本的に、MemberInfoごとのsingletonであり、Type、PropertyInfoなどにバインドされた1つのインスタンスであると思います。
ここに私のテストコードがあります:
using System;
namespace AttribTest
{
[AttributeUsage(AttributeTargets.Class)]
class MyAttribAttribute : Attribute
{
public string Value { get; set; }
public MyAttribAttribute()
: base()
{
Console.WriteLine("Created MyAttrib instance");
}
}
[MyAttrib(Value = "SetOnClass")]
class MyClass
{
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Getting attributes for MyClass.");
object[] a = typeof(MyClass).GetCustomAttributes(false);
((MyAttribAttribute)a[0]).Value = "a1";
Console.WriteLine("Getting attributes for MyClass.");
a = typeof(MyClass).GetCustomAttributes(false);
Console.WriteLine(((MyAttribAttribute)a[0]).Value);
Console.ReadKey();
}
}
}
今、 I が属性を実装する場合、出力は次のようになります。
Created MyAttrib instance
Getting attributes for MyClass.
Getting attributes for MyClass.
a1
「クラスローダー」の場所(申し訳ありませんが、.netがそのタイプをどのようにロードするかは100%確信できませんが、Javaの背景がもっとあります)MyClassをコンパイルし、MyAttribAttributeのインスタンスを作成し、どこかに一緒に格納します。 (おそらくJavaの場合、ヒープ内のPerm Gen)GetCustomAttributes()を2回呼び出すと、以前に作成された同じインスタンスが返されます。
ただし、実際の出力は次のとおりです。
Getting attributes for MyClass.
Created MyAttrib instance
Getting attributes for MyClass.
Created MyAttrib instance
SetOnClass
それで...なぜですか?呼び出しごとにこれらすべてのオブジェクトの新しいインスタンスを作成するのは少し過剰であり、パフォーマンス/メモリ管理には向いていないようです。常に同じインスタンスを何度も取得する方法はありますか?
このように設計された理由はありますか?
気にする理由は、いくつかの検証情報を内部的に保持するカスタム属性を作成したためです。そのため、属性には基本的に「private bool Validated」があります。私が真に設定したこと。検証に時間がかかるため、毎回実行する必要はありません。問題は、属性を取得するたびに属性の新しいインスタンスが作成されるため、Validatedは常に「false」であるということです。
解決
オブジェクト作成は安価です。
次のような属性があった場合
public class MyAttribute : Attribute {
public virtual string MyText { get; set; }
}
次のようなクラスに適用します
[MyAttribute(MyText="some text")]
public class MyClass {
}
そして次のようなものを取得しました
var attr =
typeof(MyClass).GetCustomAttributes(typeof(MyAttribute), false)
.Cast<MyAttribute>().Single();
次のようにプロパティを設定します
attr.MyText = "not the text we started with";
どうすべきか、そして次に電話をかけたときにどうなるか
Console.WriteLine(
typeof(MyClass).GetCustomAttributes(typeof(MyAttribute), false)
.Cast<MyAttribute>().Single().Name
);
?
他のヒント
属性はオブジェクトとしてメモリに保存されず、アセンブリ内のメタデータとしてのみ保存されます。クエリを実行すると、構築されて返されます。通常、属性はスローアウェイオブジェクトであるため、再度必要になった場合に備えてランタイムがそれらを保持するために、おそらく大量のメモリが浪費されます。
要するに、共有情報を保存する別の方法を見つける必要があります。
ドキュメント属性。
属性がメタデータに保存されるためです。 属性は、「ユーザーフレンドリーなプロパティ名」などの情報に使用する必要があります...