Visual Basic の属性

Visual Basic 言語を使用すると、プログラマは宣言の修飾子を指定できます。宣言されているエンティティに関する情報を表します。 たとえば、クラス メソッドに修飾子 PublicProtectedFriendProtected Friend、または Private を付加すると、そのアクセシビリティが指定されます。

Visual Basic では、言語によって定義された修飾子に加えて、新しい修飾子 ( 属性と呼ばれる) を作成し、新しいエンティティを宣言するときに使用することもできます。 これらの新しい修飾子は、属性クラスの宣言によって定義され、 属性ブロックを介してエンティティに割り当てられます。

"注: 属性は、実行時に .NET Framework のリフレクション API を使用して取得できます。 これらの API は、この仕様の範囲外です。

たとえば、フレームワークでは、次の例に示すように、プログラム要素からドキュメントへのマッピングを提供するために、クラスやメソッドなどのプログラム要素に配置できる Help 属性を定義できます。

<AttributeUsage(AttributeTargets.All)> _
Public Class HelpAttribute
    Inherits Attribute

    Public Sub New(urlValue As String)
        Me.UrlValue = urlValue
    End Sub

    Public Topic As String
    Private UrlValue As String

    Public ReadOnly Property Url() As String
        Get
            Return UrlValue
        End Get
    End Property
End Class

この例では、1 つの位置指定パラメーター (UrlValue) と 1 つの名前付き引数 (Topic) を持つ、HelpAttribute(略してHelp)という名前の属性クラスを定義します。

次の例では、この属性のいくつかの使用方法を示します。

<Help("http://www.example.com/.../Class1.htm")> _
Public Class Class1
    <Help("http://www.example.com/.../Class1.htm", Topic:="F")> _
    Public Sub F()
    End Sub
End Class

次の例では、 Class1Help 属性があるかどうかを確認し、関連付けられている TopicUrl 値を書き出します (属性が存在する場合)。

Module Test
    Sub Main()
        Dim type As Type = GetType(Class1)
        Dim arr() As Object = _
            type.GetCustomAttributes(GetType(HelpAttribute), True)

        If arr.Length = 0 Then
            Console.WriteLine("Class1 has no Help attribute.")
        Else
            Dim ha As HelpAttribute = CType(arr(0), HelpAttribute)
            Console.WriteLine("Url = " & ha.Url & ", Topic = " & ha.Topic)
        End If
    End Sub
End Module

属性クラス

属性クラスは、System.Attributeから派生する非ジェネリック クラスであり、MustInheritされません。 属性クラスには、属性の有効な対象、宣言で複数回使用できるかどうか、継承されるかどうかを宣言する System.AttributeUsage 属性が含まれる場合があります。 次の例では、クラス宣言とインターフェイス宣言に配置できる SimpleAttribute という名前の属性クラスを定義します。

<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Interface)> _
Public Class SimpleAttribute
    Inherits System.Attribute
End Class

次の例では、 Simple 属性のいくつかの使用方法を示します。 属性クラスの名前は SimpleAttribute ですが、この属性を使用すると、 Attribute サフィックスが省略され、名前が Simpleに短縮される場合があります。

<Simple> Class Class1
End Class

<Simple> Interface Interface1
End Interface

属性に System.AttributeUsageがない場合は、任意のターゲットに属性を配置できます ( AttributeTargets.Allと同じです)。 System.AttributeUsage属性には変数初期化子 AllowMultipleがあり、指定された宣言に対して指定された属性を複数回指定できるかどうかを指定します。 属性の AllowMultipleTrueの場合、これは 複数使用属性クラスであり、宣言で複数回指定できます。 属性の AllowMultiple が属性に対して False または指定されていない場合は、 単一使用属性クラスであり、宣言で最大 1 回指定できます。

次の例では、 AuthorAttributeという名前の複数使用属性クラスを定義します。

<AttributeUsage(AttributeTargets.Class, AllowMultiple:=True)> _
Public Class AuthorAttribute
    Inherits System.Attribute

    Private _Value As String

    Public Sub New(value As String)
        Me._Value = value
    End Sub

    Public ReadOnly Property Value() As String
        Get
            Return _Value
        End Get
    End Property
End Class

この例では、 Author 属性の 2 つの使用方法を持つクラス宣言を示します。

<Author("Maria Hammond"), Author("Ramesh Meyyappan")> _
Class Class1
End Class

System.AttributeUsage属性には、基本型で指定した場合に、この基本型から派生した型によって属性が継承されるかどうかを指定するパブリック インスタンス変数 (Inherited) があります。 Inheritedパブリック インスタンス変数が初期化されていない場合は、既定値の False が使用されます。 プロパティとイベントは属性を継承しませんが、プロパティとイベントによって定義されたメソッドは属性を継承します。 インターフェイスは属性を継承しません。

単一使用属性が継承され、派生型で指定されている場合、派生型で指定された属性は継承された属性をオーバーライドします。 複数使用属性が継承され、派生型で指定されている場合、両方の属性が派生型で指定されます。 例えば次が挙げられます。

<AttributeUsage(AttributeTargets.Class, AllowMultiple:=True, _
                Inherited:=True) > _
Class MultiUseAttribute
    Inherits System.Attribute

    Public Sub New(value As Boolean)
    End Sub
End Class

<AttributeUsage(AttributeTargets.Class, Inherited:=True)> _
Class SingleUseAttribute
    Inherits Attribute

    Public Sub New(value As Boolean)
    End Sub
End Class

<SingleUse(True), MultiUse(True)> Class Base
End Class

' Derived has three attributes defined on it: SingleUse(False),
' MultiUse(True) and MultiUse(False)
<SingleUse(False), MultiUse(False)> _
Class Derived
    Inherits Base
End Class

属性の位置パラメーターは、属性クラスのパブリック コンストラクターのパラメーターによって定義されます。 位置指定パラメーターは ByVal する必要があり、 ByRefを指定することはできません。 パブリック インスタンス変数とプロパティは、属性クラスのパブリック読み取り/書き込みプロパティまたはインスタンス変数によって定義されます。 位置指定パラメーターとパブリック インスタンス変数およびプロパティで使用できる型は、属性型に制限されます。 型は、次のいずれかの場合に属性型です。

  • DateDecimalを除く任意のプリミティブ型。

  • Object

  • System.Type

  • 列挙された型(入れ子にされた型がある場合)がアクセシビリティ Public

  • このリスト内の前のいずれかの型の 1 次元配列。

属性ブロック

属性は属性 ブロックで指定されます。 各属性ブロックは山かっこ ("<>") で区切られ、属性ブロック内のコンマ区切りリストまたは複数の属性ブロックで複数の属性を指定できます。 属性を指定する順序は重要ではありません。 たとえば、属性ブロック <A, B><B, A><A> <B><B> <A> はすべて同等です。

Attributes
    : AttributeBlock+
    ;

AttributeBlock
    : LineTerminator? '<' AttributeList LineTerminator? '>' LineTerminator?
    ;

AttributeList
    : Attribute ( Comma Attribute )*
    ;

Attribute
    : ( AttributeModifier ':' )? SimpleTypeName
    ( OpenParenthesis AttributeArguments? CloseParenthesis )?
    ;

AttributeModifier
    : 'Assembly' | 'Module'
    ;

サポートされていない一種の宣言で属性を指定することはできません。また、属性ブロックで単一使用属性を複数回指定することはできません。 次の例では、インターフェイス Interface1HelpStringを使用しようとし、Class1の宣言で複数回使用するため、エラーが発生します。

<AttributeUsage(AttributeTargets.Class)> _
Public Class HelpStringAttribute
    Inherits System.Attribute

    Private InternalValue As String

    Public Sub New(value As String)
        Me.InternalValue = value
    End Sub

    Public ReadOnly Property Value() As String
        Get
            Return InternalValue
        End Get
    End Property
End Class

' Error: HelpString only applies to classes.
<HelpString("Description of Interface1")> _
Interface Interface1
    Sub Sub1()
End Interface

' Error: HelpString is single-use.
<HelpString("Description of Class1"), _
    HelpString("Another description of Class1")> _
Public Class Class1
End Class

属性は、オプションの属性修飾子、属性名、位置引数の省略可能なリスト、および変数/プロパティ初期化子で構成されます。 パラメーターまたは初期化子がない場合は、かっこを省略できます。 属性に修飾子がある場合は、ソース ファイルの先頭にある属性ブロックに含まれている必要があります。

ソース ファイルの先頭に、ソース ファイルを含むアセンブリまたはモジュールの属性を指定する属性ブロックが含まれている場合は、属性ブロック内の各属性に、 Assembly 修飾子または Module 修飾子とコロンの両方のプレフィックスを付ける必要があります。

属性名

属性の名前は、属性クラスを指定します。 慣例により、属性クラスにはサフィックス Attributeを使用して名前が付けられます。 属性の使用には、このサフィックスを含められますが、省略もできます。 したがって、属性識別子に対応する属性クラスの名前は、識別子自体か、修飾された識別子と Attributeの連結です。 コンパイラは、属性名を解決すると、名前に Attribute を追加し、検索を試みます。 その検索が失敗した場合、コンパイラはサフィックスなしで参照を試みます。 たとえば、属性クラスの SimpleAttribute を使用すると、 Attribute サフィックスが省略され、名前が Simpleに短縮される場合があります。

<Simple> Class Class1
End Class

<Simple> Interface Interface1
End Interface

上記の例は、意味的に次と同じです。

<SimpleAttribute> Class Class1
End Class

<SimpleAttribute> Interface Interface1
End Interface

一般に、サフィックス Attribute で名前が付けられた属性をお勧めします。 次の例は、 TT``Attribute という名前の 2 つの属性クラスを示しています。

<AttributeUsage(AttributeTargets.All)> _
Public Class T
    Inherits System.Attribute
End Class

<AttributeUsage(AttributeTargets.All)> _
Public Class TAttribute
    Inherits System.Attribute
End Class

' Refers to TAttribute.
<T> Class Class1 
End Class

' Refers to TAttribute.
<TAttribute> Class Class2 
End Class

属性ブロック <T> と属性ブロックの両方 <TAttribute>TAttributeという名前の属性クラスを参照します。 クラス TAttributeの宣言を削除するまで、Tを属性として使用することはできません。

属性引数

属性の引数には、 位置引数インスタンス変数/プロパティ初期化子の 2 つの形式を使用できます。 属性の位置引数は、インスタンス変数/プロパティ初期化子の前に置く必要があります。 位置引数は、定数式、1 次元配列作成式、または GetType 式で構成されます。 インスタンス変数/プロパティ初期化子は、識別子で構成され、キーワードに一致し、コロンと等号が続き、定数式または GetType 式で終わります。

属性クラス T、位置引数リスト P、およびインスタンス変数/プロパティ初期化子リスト N属性を指定すると、引数が有効かどうかを判断します。

  1. フォーム New T(P)の式をコンパイルするには、コンパイル時の処理手順に従います。 これにより、コンパイル時エラーが発生するか、引数リストに最も適用できる T のコンストラクターが決定されます。

  2. 手順 1 で決定されたコンストラクターに属性型ではないパラメーターや宣言サイトでアクセスできないパラメーターがある場合は、コンパイル時エラーが発生します。

  3. NArgされるインスタンス変数/プロパティ初期化子ごとに、インスタンス変数/プロパティ初期化子Argの識別子Nameします。 Nameは、型が属性型であるTで、Shared、書き込み可能、Publicのインスタンス変数またはパラメーターなしのプロパティを識別する必要があります。 Tにそのようなインスタンス変数またはプロパティがない場合は、コンパイル時エラーが発生します。

例えば次が挙げられます。

<AttributeUsage(AttributeTargets.All)> _
Public Class GeneralAttribute
    Inherits Attribute

    Public Sub New(x As Integer)
    End Sub

    Public Sub New(x As Double)
    End Sub

    Public y As Type

    Public Property z As Integer
        Get
        End Get

        Set
        End Set
    End Property
End Class

' Calls the first constructor.
<General(10, z:=30, y:=GetType(Integer))> _
Class C1
End Class

' Calls the second constructor.
<General(10.5, z:=10)> _
Class C2
End Class

型パラメーターは、属性引数のどこにも使用できません。 ただし、構築された型を使用できます。

<AttributeUsage(AttributeTargets.All)> _
Class A 
   Inherits System.Attribute 

   Public Sub New(t As Type)
   End Sub 
End Class

Class List(Of T) 
    ' Error: attribute argument cannot use type parameter
    <A(GetType(T))> Dim t1 As T 

    ' OK: closed type
    <A(GetType(List(Of Integer)))> Dim y As Integer
End Class
AttributeArguments
    : AttributePositionalArgumentList
    | AttributePositionalArgumentList Comma VariablePropertyInitializerList
    | VariablePropertyInitializerList
    ;

AttributePositionalArgumentList
    : AttributeArgumentExpression? ( Comma AttributeArgumentExpression? )*
    ;

VariablePropertyInitializerList
    : VariablePropertyInitializer ( Comma VariablePropertyInitializer )*
    ;

VariablePropertyInitializer
    : IdentifierOrKeyword ColonEquals AttributeArgumentExpression
    ;

AttributeArgumentExpression
    : ConstantExpression
    | GetTypeExpression
    | ArrayExpression
    ;