web-dev-qa-db-ja.com

C#でカスタム属性を作成する方法

私は何度も試しましたが、それでもカスタム属性の使用法を理解することはできません(多くのリンクを既に通過しました)。

コードを使用してカスタム属性の非常に基本的な例を誰かに説明してもらえますか?

109
slash shogdhe

カスタム Attribute を作成するコードはかなり単純ですが、属性とは何かを理解することは非常に重要です:

属性は、プログラムにコンパイルされたメタデータです。属性自体は、クラス、プロパティ、またはモジュールに機能を追加するのではなく、データを追加します。ただし、リフレクションを使用すると、機能を作成するためにこれらの属性を活用できます。

したがって、たとえば、 エンタープライズアプリケーションライブラリ から 検証アプリケーションブロック を見てみましょう。コード例を見ると、次のことがわかります。

    /// <summary>
    /// blah blah code.
    /// </summary>
    [DataMember]
    [StringLengthValidator(8, RangeBoundaryType.Inclusive, 8, RangeBoundaryType.Inclusive, MessageTemplate = "\"{1}\" must always have \"{4}\" characters.")]
    public string Code { get; set; }

上記のスニペットから、コードは変更されるたびに、Validatorのルールに応じて常に検証されることが推測されます(この例では、少なくとも8文字、最大8文字)。しかし、実際には、属性は何もせず、プロパティにメタデータを追加するだけです。

ただし、エンタープライズライブラリには、オブジェクトを調べるValidation.Validateメソッドがあり、各プロパティについて、コンテンツが属性によって通知されたルールに違反しているかどうかをチェックします。

そのため、属性について考える必要があります。これは、後で他のメソッド/クラス/などで使用される可能性のあるコードにデータを追加する方法です。

91
Bruno Brant

Attribute から派生するクラスを書くことから始めます。

public class MyCustomAttribute: Attribute
{
    public string SomeProperty { get; set; }
}

次に、この属性で何でも(クラス、メソッド、プロパティなど)を装飾できます。

[MyCustomAttribute(SomeProperty = "foo bar")]
public class Foo
{

}

最後に、リフレクションを使用してそれを取得します。

var customAttributes = (MyCustomAttribute[])typeof(Foo).GetCustomAttributes(typeof(MyCustomAttribute), true);
if (customAttributes.Length > 0)
{
    var myAttribute = customAttributes[0];
    string value = myAttribute.SomeProperty;
    // TODO: Do something with the value
}

AttributeUsage 属性を使用して、このカスタム属性を適用できるターゲットタイプを制限できます。

/// <summary>
/// This attribute can only be applied to classes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class MyCustomAttribute : Attribute

属性について知っておくべき重要事項:

  • 属性はメタデータです。
  • それらはcompile-timeでアセンブリにベイクされます。これは、プロパティの設定方法に非常に深刻な影響を及ぼします。定数(コンパイル時に既知)の値のみが受け入れられます
  • カスタム属性を理解して使用する唯一の方法は、 Reflection を使用することです。したがって、実行時にリフレクションを使用してそれらを取得し、カスタム属性で何かを装飾しなければ、あまり起こることを期待しないでください。
  • 属性の作成時間は非決定的です。それらはCLRによってインスタンス化され、ユーザーはまったく制御できません。
250
Darin Dimitrov

活用/コピー ダリン・ディミトロフの素晴らしい応答 、これはクラスではなくプロパティのカスタム属性にアクセスする方法です:

[クラスFoo]の装飾プロパティ:

[MyCustomAttribute(SomeProperty = "This is a custom property")]
public string MyProperty { get; set; }

それを取得する:

PropertyInfo propertyInfo = typeof(Foo).GetProperty(propertyToCheck);
object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
if (attribute.Length > 0)
{
    MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
    string propertyValue = myAttribute.SomeProperty;
}

これをループでスローし、リフレクションを使用して、クラスFooeachプロパティのこのカスタム属性にアクセスすることもできます。

foreach (PropertyInfo propertyInfo in Foo.GetType().GetProperties())
{
    string propertyName = propertyInfo.Name;

    object[] attribute = propertyInfo.GetCustomAttributes(typeof(MyCustomAttribute), true);
    // Just in case you have a property without this annotation
    if (attribute.Length > 0)
    {
        MyCustomAttribute myAttribute = (MyCustomAttribute)attribute[0];
        string propertyValue = myAttribute.SomeProperty;
        // TODO: whatever you need with this propertyValue
    }
}

ありがとう、ダリン!!

20
Hopper