C# 属性(Attribute)

属性(Attribute)属性(Attribute)は、クラス、メソッド、構造体、列挙型、コンポーネントなど、プログラム内のさまざまな要素の動作情報を実行時に渡すために使用される宣言型ラベルです。属性を使用することで、プログラムに宣言型情報を追加できます。宣言型ラベルは、適用先の要素の前に置かれる角かっこ([ ])で記述されます。

属性(Attribute)は、コンパイラ指令やコメント、説明、メソッド、クラスなどのその他の情報といったメタデータを追加するために使用されます。.NET Framework には、次の 2 種類の属性が用意されています。定義済み属性とカスタム属性。

属性(Attribute)の指定

属性(Attribute)を指定する構文は次のとおりです:

[attribute(positional_parameters, name_parameter = value, ...)]
element

属性(Attribute)の名前と値は角かっこ内に指定され、適用先の要素の前に置かれます。positional_parameters は必須情報を指定し、name_parameter はオプション情報を指定します。

定義済み属性(Attribute)

.NET Framework には、次の 3 つの定義済み属性があります。

  • AttributeUsage
  • Conditional
  • Obsolete

AttributeUsage

定義済み属性AttributeUsageカスタム属性クラスの使用方法を説明します。属性を適用できる項目の種類を指定します。

この属性を指定する構文は次のとおりです:

[AttributeUsage(
   validon,
   AllowMultiple=allowmultiple,
   Inherited=inherited
)]

ここで:

  • パラメータ validon は、属性を配置できる言語要素を指定します。これは列挙子AttributeTargetsの値の組み合わせです。デフォルトは AttributeTargets.All。
  • パラメータallowmultiple(省略可能) この属性のAllowMultipleプロパティにブール値を指定します。true の場合、その属性は複数回使用できます。デフォルトは false(単一使用)です。
  • パラメータinherited(省略可能) この属性のInheritedプロパティにブール値を指定します。true の場合、その属性は派生クラスに継承されます。デフォルトは false(継承されません)です。

例:

[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property, 
AllowMultiple = true)]

Conditional

この定義済み属性は、指定されたプリプロセッサ識別子に実行が依存する条件メソッドをマークします。

指定された値(たとえばDebug 或 Traceなど)に応じて、メソッド呼び出しの条件付きコンパイルを引き起こします。たとえば、コードをデバッグするときに変数の値を表示します。

この属性を指定する構文は次のとおりです:

[Conditional(
   conditionalSymbol
)]

例:

[Conditional("DEBUG")]

次の例は、この属性を示しています:

例

#define DEBUG
using System;
using System.Diagnostics;
public class Myclass
{
    [Conditional("DEBUG")]
    public static void Message(string msg)
    {
        Console.WriteLine(msg);
    }
}
class Test
{
    static void function1()
    {
        Myclass.Message("In Function 1.");
        function2();
    }
    static void function2()
    {
        Myclass.Message("In Function 2.");
    }
    public static void Main()
    {
        Myclass.Message("In Main function.");
        function1();
        Console.ReadKey();
    }
}

上記のコードをコンパイルして実行すると、次の結果が生成されます:

In Main function.
In Function 1.
In Function 2.

Obsolete

この定義済み属性は、使用すべきではないプログラムエンティティをマークします。特定のターゲット要素を破棄するようコンパイラに通知できます。たとえば、クラスで新しいメソッドが使用されているが、クラス内の古いメソッドも保持したい場合、新しいメソッドを古いメソッドの代わりに使用すべきであるというメッセージを表示して、その古いメソッドを obsolete(非推奨)としてマークできます。

この属性を指定する構文は次のとおりです:

[Obsolete(
   message
)]
[Obsolete(
   message,
   iserror
)]

ここで:

  • パラメータmessageは、項目がなぜ非推奨なのか、および代わりに何を使用すべきかを説明する文字列です。
  • パラメータiserrorはブール値です。この値が true の場合、コンパイラはその項目の使用をエラーとして扱います。デフォルトは false(コンパイラは警告を生成します)です。

次の例は、この属性を示しています:

例

using System;
public class MyClass
{
   [Obsolete("Don't use OldMethod, use NewMethod instead", true)]
   static void OldMethod()
   {
      Console.WriteLine("It is the old method");
   }
   static void NewMethod()
   {
      Console.WriteLine("It is the new method");
   }
   public static void Main()
   {
      OldMethod();
   }
}

プログラムをコンパイルしようとすると、コンパイラは次のエラーメッセージを表示します:

 Don't use OldMethod, use NewMethod instead

カスタム属性(Attribute)の作成

.NET Framework では、宣言型情報を格納し、実行時に取得できるカスタム属性を作成できます。この情報は、設計基準とアプリケーションのニーズに応じて、任意のターゲット要素に関連付けることができます。

カスタム属性を作成して使用するには、次の 4 つの手順があります:

  • カスタム属性の宣言
  • カスタム属性の構築
  • ターゲットのプログラム要素へのカスタム属性の適用
  • リフレクションによる属性へのアクセス

最後の手順では、メタデータを読み取ってさまざまなシンボルを検索する簡単なプログラムを作成します。メタデータは、他のデータを記述するためのデータと情報です。このプログラムはリフレクションを使用して、実行時に属性にアクセスする必要があります。これについては次の章で詳しく説明します。

カスタム属性の宣言

新しいカスタム属性は、System.Attributeクラスから派生させる必要があります。例:

// 一个自定义特性 BugFix 被赋给类及其成员
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]

public class DeBugInfo : System.Attribute

上記のコードでは、DeBugInfoという名前のカスタム属性を宣言しました。

カスタム属性の構築

次の名前のカスタム属性を構築しましょう:DeBugInfoこのカスタム属性は、デバッグプログラムから取得した情報を格納します。次の情報を格納します:

  • バグのコード番号
  • そのバグを特定した開発者の名前
  • コードを最後にレビューした日付
  • 開発者がマークした文字列メッセージを格納します

私たちのDeBugInfoクラスには、最初の 3 つの情報を格納するための 3 つのプライベートプロパティと、メッセージを格納するための 1 つのパブリックプロパティがあります。したがって、バグ番号、開発者名、レビュー日付は DeBugInfo クラスの必須の位置(positional)引数になり、メッセージはオプションの名前付き(named)引数になります。

各属性には少なくとも 1 つのコンストラクタが必要です。必須の位置(positional)引数はコンストラクタを介して渡す必要があります。次のコードは、DeBugInfoクラス:

例

// カスタム属性 BugFix がクラスとそのメンバーに割り当てられます
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]

public class DeBugInfo : System.Attribute
{
  private int bugNo;
  private string developer;
  private string lastReview;
  public string message;

  public DeBugInfo(int bg, string dev, string d)
  {
      this.bugNo = bg;
      this.developer = dev;
      this.lastReview = d;
  }

  public int BugNo
  {
      get
      {
          return bugNo;
      }
  }
  public string Developer
  {
      get
      {
          return developer;
      }
  }
  public string LastReview
  {
      get
      {
          return lastReview;
      }
  }
  public string Message
  {
      get
      {
          return message;
      }
      set
      {
          message = value;
      }
  }
}

カスタム属性の適用

属性を、適用対象の直前に配置することで、属性を適用します:

例

[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectangle
{
  // メンバー変数
  protected double length;
  protected double width;
  public Rectangle(double l, double w)
  {
      length = l;
      width = w;
  }
  [DeBugInfo(55, "Zara Ali", "19/10/2012",
  Message = "Return type mismatch")]
  public double GetArea()
  {
      return length * width;
  }
  [DeBugInfo(56, "Zara Ali", "19/10/2012")]
  public void Display()
  {
      Console.WriteLine("Length: {0}", length);
      Console.WriteLine("Width: {0}", width);
      Console.WriteLine("Area: {0}", GetArea());
  }
}

次の章では、Reflection クラスオブジェクトを使用してこれらの情報を取得します。

その他の拡張