Creating Custom Attributes


Visual Basic .NET Unleashed
By Paul Kimmel
Table of Contents
Chapter 12.  Defining Attributes

Creating Custom Attributes

First and foremost, attributes are classes that are subclassed from the System.Attribute class. The implication is that all the skills you have acquired can be used to generalize the Attribute class and define custom attributes.

Custom attributes allow third parties to participate in extending the .NET framework. To demonstrate creating custom attributes, I will walk you through creating the HelpAttribute introduced in the VS .NET documentation. Let's review a couple of guidelines for creating custom attributes first.

  • Add the Attribute suffix to the attribute class name .

  • Apply the AttributeUsageAttribute to the custom attribute class, indicating intended usage.

  • Use positional arguments for required information.

  • Use named parameters for optional information.

  • Arguments should not be both named and positional.

  • Use read-only properties for positional properties. (You can use the F prefix for the field and drop the F for the property name.)

  • Include a readable and writable property for named arguments.

These guidelines are provided to facilitate custom attribute implementation and keep you out of trouble. Like any guidelines, they exist for your benefit, but you can experiment with slight variations and deviate from the guidelines if you have a good reason.

Implementing the HelpAttribute

The HelpAttribute sample class defined in this section was borrowed from the VS .NET help documentation. The original reference is located at ms-help://MS. VSCC/MS.MSDNVS/cpguide/html/cpconwritingcustomattributes. htm#cpconcustomattributeexample.

You can reference that document to find additional information on creating custom attributes. The specific requirements for creating custom attributes are covered here.

Declaring the Attribute Class

Attributes are used by other applications and effectively extend VS .NET resources. You will need to create a Class Library project to end up with a .DLL assembly. By default a Class Library template adds a .vb module with a class defined in it. This is what we need.

After you create the new Class Library, rename the project MyHelpAttribute and rename the class HelpAttribute. The result is a .vb module with the following lines of code:

 Public Class HelpAttribute End Class 

The rest is almost as easy if you know what each step is and the role of each part of the process.

Specifying AttributeUsage

The next step is to indicate what entities the attribute will be used to describe. We want to allow developers to associate help with any code entity; hence we will indicate this information in AttributeUsageAttribute.

AttributeUsageAttribute defines one positional argument and supports two named arguments. The positional argument indicates the AttributeTargets, and the two named arguments are AllowMultiple and Inherited.

Using the AttributeTargets Argument

AttributeTargets describes the entities that the attribute can be applied to. AttributeTargets is an enumeration. (You can look it up in the help documentation for specifics, but the enumerations are just the names of kinds of code entities: Class, Property, Assembly, Enum, and so forth.)

To indicate that our attribute is suitable for all targets we can add AttributeUsageAttribute to our code, which evolves as follows :

 <AttributeUsage(AttributeTargets.All)> Public Class HelpAttribute End Class 

Remember that by convention the Attribute suffix is dropped when applied.

Using the AllowMultiple Argument

AllowMultiple is a named argument. From the earlier guidelines, we know that named arguments are used for optional arguments. AllowMultiple is False by default; it indicates whether a given attribute can be applied more than once to the same entity. For our purposes, each entity only needs one help reference.

Attributes that are defined with AllowMultiple:=True are referred to as multiuse attributes. When AllowMultiple:=False, you have a single-use attribute.

Using the Inherited Argument

Inherited is a named argument. Recall that named arguments are passed using the Name := Value syntax between the parentheses and after the positional arguments.

The Inherited named argument is False by default. Inherited indicates whether or not the attribute can be subclassed.

Inheriting from System.Attribute

After we have specified attribute usage, we need to indicate that we are generalizing, or subclassing, the attribute class. The attribute class we are developing evolves as shown.

 <AttributeUsage(AttributeTargets.All)> Public Class HelpAttribute   Inherits System.Attribute End Class 
Implementing the Constructor

We determined that the URN is a positional argument. That is, the URN is a required argument. Consequently this choice guides the implementation of our constructor. We also need a field to store the value in and a read-only property to provide public access to the underlying field.

Applying these choices, we can update the class:

 <AttributeUsage(AttributeTargets.All)> Public Class HelpAttribute   Inherits System.Attribute   Private FUrn As String   Public ReadOnly Property Urn() As String     Get       Return FUrn     End Get   End Property   Public Sub New(ByVal AUrn As String)     FUrn = AUrn   End Sub End Class 

The revision adds the private field, using our F-prefix convention. The read-only property provides public access to the private field, also a convention we employ in object-oriented programming. Finally, the constructor specifies the required positional argument used to initialize the URN, or location, of the help content.

Adding Named Arguments

Finally, we can add named arguments to our attribute class. Named arguments are public fields or private fields represented by public readable and writable properties. (Notice that named arguments are writable.)

Generally, we use private fields and public properties. However, in this case we will deviate and simply add a public field to represent our named argument, Topic. As a final touch, I elected to make the positional argument optional and have HelpAttribute default to my Web site. (In your application you could have this attribute default to your root help document.) Listing 12.11 shows the completed attribute class.

Listing 12.11 A completed HelpAttribute attribute class
  1:  Imports System  2:   3:  <AttributeUsage(AttributeTargets.All)> _  4:  Public Class HelpAttribute  5:  Inherits Attribute  6:   7:  Private FUrn As String  8:  Public Topic As String  9:   10:  Public ReadOnly Property Urn() As String  11:  Get  12:  Return FUrn  13:  End Get  14:  End Property  15:   16:  Public Sub New(Optional ByVal AUrn As String _  17:  = "")  18:  FUrn = AUrn  19:  End Sub  20:   21:  End Class 

The completed class is quite short, but the attribute allows us to tag any elements of code we choose with any documentation we want.


Visual BasicR. NET Unleashed
Visual BasicR. NET Unleashed
Year: 2001
Pages: 222 © 2008-2017.
If you may any questions please contact us: