FREE hit counter and Internet traffic statistics from freestats.com

Tuesday, April 27, 2004

Using .NET Attributes

I'm sometimes asked why a developer might want to implement custom attributes in .NET. Here is a great example by Jerry Dixon. Another example is to provide custom evidence the Code Access Security system.

For those not familiar with attributes here's a little primer from my book Building Distributed Applications with Visual Basic .NET...

In addition to simply using attributes exposed by the framework, you can create your own attributes to specify custom metadata. For example, if you were designing a set of framework classes to be widely distributed, you could create a custom attribute to encapsulate information about reference documentation.

To create a custom attribute, you simply need to create a new class that derives from System.Attribute. Listing 2.3 illustrates creating a custom attribute called DocumentationAttribute to include documentation information.

Note: It is customary to add the suffix "Attribute" to the name of the attribute; however, clients that use the attribute needn't include this part of the name.

Listing 2.3 Creating a Custom Attribute. This class implements a custom attribute for documentation purposes.

<AttributeUsage(AttributeTargets.Class Or _

AttributeTargets.Interface Or AttributeTargets.Enum Or _
AttributeTargets.Struct)> _
Public Class DocumentationAttribute : Inherits Attribute

Private strUrl As String
Private strAuthor As String

Public Sub New(ByVal url As String)
Me.strUrl = url
End Sub

Public Property Author() As String
Get
Return strAuthor
End Get
Set(ByVal Value As String)
strAuthor = Value
End Set
End Property

Public ReadOnly Property Url() As String
Get
Return strUrl
End Get
End Property

End Class


In Listing 2.3, even before the class is declared, it too uses an attribute called AttributeUsage to control on which types of entities the attribute can be placed. In this case, the Or operator is used with constants from the AttributeTargets enumeration to indicate that the DocumentationAttribute can be placed on a class, interface, enumerated type, or structure only.

Tip: To allow an attribute to be placed anywhere, you can use AttributeTargets.All. The AttributeUsageAttribute also exposes an AllowMultiple Boolean property that indicates whether multiple instances of the attribute can be placed on the same entity.

Also notice that this attribute contains two properties, Author and Url, and that Url is passed to the constructor and is required.

Users of the attribute then can decorate their classes with the DocumentationAttribute as follows:

<Documentation("http://www.quilogy.com/qa/dataaccess.aspx", _

Author:="Dan Fox")> _
Public Class QuilogyDataAccess


As noted previously, "Attribute" can be omitted from the declaration, and because the Author property is not found in the constructor, it can be added to the declaration using the := assignment operator.

At runtime, a client of the class that declared the attribute can read the attribute information using the GetCustomAttributes method of the Type object. For example, the following code uses the GetType function to return the Type object for QuilogyDataAccess from the previous code example:

Dim type As Type = GetType(QuilogyDataAccess)

Dim arr() As Object
Dim att As Attribute

arr = type.GetCustomAttributes(False)
For Each att In arr
If TypeOf att Is DocumentationAttribute Then
Dim da As DocumentationAttribute = _
CType(arr(0), DocumentationAttribute)
Console.WriteLine("Url = " & da.Url & "Author = " & da.Author)
End If
Next


It then retrieves an array of custom attributes using the GetCustomAttributes methods and walks through the array looking for the DocumentationAttribute using the TypeOf statement. When found, it converts the Object to the DocumentationAttribute type so that its properties, Url and Author, can be queried.

No comments: