実行時に属性を追加したり、実行時に属性の値を変更したりすることはできますか?
10 に答える
これは、正確に何を達成しようとしているかによって異なります。
System.ComponentModel.TypeDescriptorのものを使用して、型、プロパティ、およびオブジェクト インスタンスに属性を追加できますが、それらのプロパティを取得するためにも使用する必要があるという制限があります。これらの属性を使用するコードを作成していて、それらの制限内で生活できる場合は、間違いなくそれをお勧めします。
私の知る限り、BCL で TypeDescriptor を使用するのは、PropertyGrid コントロールとビジュアル スタジオ デザイン サーフェイスだけです。実際、彼らが本当にしなければならないことの約半分は、この方法で行っています。
属性は静的メタデータです。アセンブリ、モジュール、型、メンバー、パラメーター、および戻り値は、C# のファースト クラス オブジェクトではありません (たとえば、System.Typeクラスは単に型の反映された表現です)。型の属性のインスタンスを取得し、書き込み可能な場合はプロパティを変更できますが、型に適用される属性には影響しません。
まあ、違いますが、Reflection.Emit を使用してそうする方法について言及している記事を見つけました。
リンクは次のとおりです: http://www.codeproject.com/KB/cs/dotnetattributes.aspx、可能なアプローチが議論されているため、記事の下部にあるコメントのいくつかも調べたいと思うでしょう。
できません。1 つの回避策として、実行時に派生クラスを生成し、属性を追加することが考えられますが、これはおそらくやり過ぎです。
いいえ、ちがいます。
属性はメタデータであり、コンパイルされたアセンブリにバイナリ形式で格納されます(これが、属性で単純な型のみを使用できる理由でもあります)。
私はそうは思わない。私が間違っていたとしても、あなたが望むことができる最善のことは、タイプのインスタンスではなく、タイプ全体にそれらを追加することです。
動的に追加できるものが必要な場合、c# 属性は適していません。データをxmlに保存することを検討してください。私は最近、属性を使用して開始したプロジェクトを行いましたが、最終的には xml を使用したシリアル化に移行しました。
なぜあなたはする必要があるのですか?属性はリフレクションのための追加情報を提供しますが、必要なプロパティが外部的にわかっている場合は、属性は必要ありません。
メタデータを外部のデータベースまたはリソース ファイルに比較的簡単に保存できます。
以下の Deczaloth のコメントで述べたように、メタデータはコンパイル時に修正されると思います。GetType() をオーバーライドする動的オブジェクトを作成するか、GetCustomType() を使用して独自の型を作成することで、これを実現しています。これを使用すると、次のことができます...
私は System.ComponentModel.TypeDescriptor で非常に努力しましたが、成功しませんでした。それは機能しないという意味ではありませんが、そのためのコードを見たいと思います。
反対に、いくつかの属性値を変更したかったのです。その目的のためにうまく機能する2つの機能を実行しました。
// ************************************************************************
public static void SetObjectPropertyDescription(this Type typeOfObject, string propertyName, string description)
{
PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
var att = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
if (att != null)
{
var fieldDescription = att.GetType().GetField("description", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldDescription != null)
{
fieldDescription.SetValue(att, description);
}
}
}
// ************************************************************************
public static void SetPropertyAttributReadOnly(this Type typeOfObject, string propertyName, bool isReadOnly)
{
PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
var att = pd.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
if (att != null)
{
var fieldDescription = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldDescription != null)
{
fieldDescription.SetValue(att, isReadOnly);
}
}
}
Java では、マップを使用して独自の Key-Value コーディングを実装することで、これを回避していました。
http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html