|< Day Day Up >|
An instance of an attribute class is applied to a declaration by enclosing a constructor call in angle brackets ( <> ). Attributes always come before any regular modifiers. The following example applies the System.ThreadStaticAttribute attribute (which makes a Shared field's storage unique for each thread) to a field.
Class Test <ThreadStatic> Public Shared x As Integer End Class
Frequently, attribute constructors will have parameters that allow extra information to be specified as part of the attribute application. Arguments to an attribute follow the name of the attribute in parentheses, exactly as if they were constructor arguments. For example, the System.ObsoleteAttribute attribute (which is used to mark methods that are obsolete) takes a String as a parameter.
<System.Obsolete("This API should not be called.")> _ Sub Test() ... End Sub
Attributes also can have properties that can be used to store optional information. For example, the System.AttributeUsageAttribute attribute (which is used to define new attributes, as shown in the next section) has two properties, AllowMultiple and Inherited , which are optional values. Values are assigned to properties in the same way that named arguments are used in normal method invocation: The name of the property is followed by a colon equals ( := ) and the value. Like named arguments, properties must follow regular arguments in the argument list. The following code shows two uses of AttributeUsage , one with values set to the properties, one without.
<System.AttributeUsage(AttributeTargets.All)> _ Class FirstAttribute Inherits Attribute End Class <AttributeUsage(AttributeTargets.All, _ AllowMultiple := True, _ Inherited := False)> _ Class SecondAttribute Inherits Attribute End Class
Attributes can be placed anywhere that access modifiers, such as Public and Private , can be placed. In addition, attributes can be placed
The last two points bear some discussion. Attributes may be placed on the return type of a function primarily so that COM marshalling in formation (using the System.Runtime.InteropServices.MarshalAsAttribute ) can be applied to function return types. The attribute is placed right before the function return type's name. For example, the following declaration applies an attribute to the return type of the function F .
Imports System.Runtime.InteropServices Class Test Function F() As <MarshalAs(UnmanagedType.I4)> Integer ... End Function End Class
It is also possible to define attributes that apply to the assembly or .NET Framework module being produced by the compiler. (.NET Framework modules are a special type of assembly that can be linked together to produce a single assembly. Their usage is beyond the scope of this book.) To apply an attribute to the assembly or Framework module as a whole, you can specify an attribute by itself after any Option or Imports statements. The attribute name must be preceded by " assembly: " for attributes that apply to the assembly, or " module: " for attributes that apply to Framework modules. At compile time, all the attributes applied to the assembly or Framework module are combined. For example, the following code shows the usage of the System.Reflection.AssemblyDescriptionAttribute attribute.
Imports System.Reflection <Assembly: AssemblyDescription("A test program.")> Module Test Sub Main() Console.WriteLine("Test.") End Sub End Module
Some attributes can be applied multiple times to a declaration. For example, the System.ObsoleteAttribute attribute can be applied only once, but the System.Diagnostics.ConditionalAttribute attribute (which allows method calls to be compiled on a conditional basis) can be applied multiple times.
Module Test <Obsolete("Don't call this API."), _ Diagnostics.Conditional("DEBUG"), _ Diagnostics.Conditional("TEST")> _ Sub Main() Console.WriteLine("Test.") End Sub End Module
Attributes applied to a class are, by default, inherited by any classes that derive from that class. Overriding a method does not remove the attributes applied to the method being overridden. If an overriding method specifies the same attribute as the method being overridden, the behavior depends on whether or not the attribute can be applied multiple times: If the attribute can be used multiple times, the overriding attribute complements the overridden attribute; if the attribute is single-use , the overriding attribute replaces the overridden attribute.
|< Day Day Up >|