C#で属性を動的に追加できますか?


回答:


67

属性は静的メタデータです。アセンブリ、モジュール、型、メンバー、パラメーター、および戻り値は、C#のファーストクラスオブジェクトではありません(たとえば、System.Typeクラスは型の反映表現にすぎません)。タイプの属性のインスタンスを取得し、書き込み可能であればプロパティを変更できますが、タイプに適用されるため、属性には影響しません。


68

これは実際に何を達成しようとしているのかに依存します。

System.ComponentModel.TypeDescriptorのものは種類、プロパティとオブジェクトインスタンスに属性を追加するために使用することができ、そしてそれはあなたがよくて、これらのプロパティを取得するためにそれを使用する必要がないという制限があります。これらの属性を使用するコードを記述していて、それらの制限の範囲内で生活できる場合は、間違いなくお勧めします。

私の知る限りでは、PropertyGridコントロールとビジュアルスタジオのデザインサーフェイスだけが、TypeDescriptor要素を使用するBCL内の唯一のものです。実際、それは彼らが本当にする必要があることの約半分をする方法です。


7
実際には、ほとんどのデータ・バインディングを使用TypeDescriptor-だけではなくPropertyGrid
マークグラベル

1
Silverlightのプロジェクト(ここにプロパティメタデータ属性を追加するために、任意の回避策TypeDescriptorTypeDescriptionProvider?実装されていない
シミーWeitzhandler

1
TypeDescriptor.GetAttributes()は重複した属性を処理しないことに注意してください。最後の属性タイプのみを選択します。元[Attr(1), Attr(2), Attr(3)]のみAttr(3)が見つかりました。
ohmusama 2013年

11

できません。回避策の1つは、実行時に派生クラスを生成して属性を追加することですが、これはおそらくやり過ぎです。


10

まあ、違いますが、Reflection.Emitを使用して参照する記事を見つけました。

ここにリンクがあります:http : //www.codeproject.com/KB/cs/dotnetattributes.aspx、考えられるアプローチについて説明しているので、記事の下部にあるコメントのいくつかを確認することもできます。


10
実行時にReflection.Emitクラスを使用して属性を作成できますが、既存のクラスではなく、Emitパッケージで構築したクラスに属性をバインドできることに注意してください。
Panos

どのような役に立たない答え=))ここでは、動的なクラスではなく、既存のクラスを気にします。
絶望的な

@Hopeless、あなたはにサブクラスYourClass化するかもしれませんYourRuntimeClassWithAttributes
モート

@Motes意味がわからない。私のクラスはすべて事前に定義されている。つまり、(私のクラスが継承する)すべての基本クラスも事前に定義/決定する必要がある。Reflection.Emitを使用して動的に作成されたものに関与する方法は考えられません。
絶望的な

1
@Hopeless、既存のクラスに属性を動的に追加するYourClass場合は、実行時にそれをサブクラス化し、目的の動的に作成された属性も持つわずかに異なる名前で同一のクラスを生成できます。ポリモーフィズムにより、型チェックコードで識別できます。あなたのベースクラス。
モート

4

いいえ、ちがいます。

属性はメタデータであり、コンパイルされたアセンブリにバイナリ形式で格納されます(これは、属性で単純型のみを使用できる理由でもあります)。


3

私はそうは思いません。私が間違っているとしても、あなたが期待できる最善の方法は、それらをTypeのインスタンスではなく、Type全体に追加することです。


22
TypeDescriptor.AddAttributes(Object、Attribute [])は、クラスレベルの属性をターゲットコンポーネントインスタンスに追加します。
Peter Wone 2008年

3

動的に追加できるものが必要な場合は、c#属性を使用することはできません。データをxmlに保存する方法を調べます。私は最近、属性付きで開始したプロジェクトを行いましたが、最終的にはxml付きのシリアル化に移行しました。


1
多分それは美しい方法ではないかもしれませんが、他の多くのライブラリが使用することを選択する方法であり、それらのライブラリの動作をカスタマイズするために、リフレクション=))を実際にデッドロックで遊ぶ必要があります。
希望のない

3

なぜする必要があるのですか?属性はリフレクションのための追加情報を提供しますが、必要なプロパティが外部でわかっている場合は必要ありません。

データベースまたはリソースファイルに比較的簡単に外部からメタデータを保存できます。


1
ボイラープレートの除去。クラスに、クラス内のコードに基づいて自動的に属性を生成させることができれば便利ではないでしょうか。SQL CLRオブジェクトのボイラープレートを減らすために、このようなことを理解しようとしています。他の言語では簡単でしょう... paulgraham.com/avg.htmlを
Duncan Bayne

1

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);
                }
            }
        }

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.