Custom Attributes

Team-Fly    

 
Application Development Using Visual Basic and .NET
By Robert J. Oberg, Peter Thorsteinson, Dana L. Wyatt
Table of Contents
Chapter 10.  .NET Framework Classes


Chapter 6 introduced the concept of attributes, which have already appeared in several examples. In this chapter we used the Serializable and Synchronization attributes, which are provided by .NET Framework classes. The .NET Framework makes the attribute mechanism entirely extensible, allowing you to define custom attributes, which can be added to a class's metadata. This custom metadata is available through reflection and can be used at runtime. To simplify the use of custom attributes, you may declare a base class to do the work of invoking the reflection API to obtain the metadata information.

The example CustomAttribute illustrates the custom attribute InitialDirectory . InitialDirectory controls the initial current directory where the program runs. By default, the current directory is the directory containing the program's executable. In the case of a Visual Studio .NET project built in Debug mode, this directory is \ bin , relative to the project source code directory.

Using a Custom Attribute

Before we discuss implementing the custom attribute, let us look at how the InitialDirectory attribute is used. To be able to control the initial directory for a class, we derive the class from the base class DirectoryContext . We may then apply to a class the attribute InitialDirectory , which takes a String parameter giving a path to what the initial directory should be. The property DirectoryPath extracts the path from the metadata. If our class does not have the attribute applied, this path will be the default. Here is the code for our test program.

When you run this sample on your system, you can change the directory in the attribute to any directory that exists on your machine.

 ' CustomAttribute.vb Imports System Imports System.IO Class Normal    Inherits DirectoryContext End Class <InitialDirectory("c:\")> Class Special    Inherits DirectoryContext End Class Public Module AttributeDemo    Public Sub Main()       Dim objNormal As Normal = New Normal()       Console.WriteLine(_          "path = {0}", objNormal.DirectoryPath)       ShowDirectoryContents(objNormal.DirectoryPath)       Dim objSpecial As Special = New Special()       Console.WriteLine(_          "path = {0}", objSpecial.DirectoryPath)       ShowDirectoryContents(objSpecial.DirectoryPath)    End Sub    Private Sub ShowDirectoryContents(ByVal path As String)       Dim dir As DirectoryInfo = New DirectoryInfo(path)       Dim files() As FileInfo = dir.GetFiles()       Console.WriteLine("Files:")       Dim f As FileInfo       For Each f In files          Console.WriteLine("   {0}", f.Name)       Next       Dim dirs() As DirectoryInfo = dir.GetDirectories()       Console.WriteLine("Directories:")       Dim d As DirectoryInfo       For Each d In dirs          Console.WriteLine("   {0}", d.Name)       Next    End Sub End Module 

Here is the output:

 path = C:\OI\NetVB\Chap10\CustomAttribute\bin Files:    CustomAttribute.exe    CustomAttribute.pdb Directories: path = c:\ Files:    BOOTLOG.TXT    MSDOS.SYS    DETLOG.TXT    BOOTLOG.PRV    OAKCDROM.SYS    AUTOEXEC.BAT    SETUPLOG.TXT    VIDEOROM.BIN    LOGO.SYS    command.com    SUHDLOG.DAT    NETLOG.TXT    CONFIG.BAK 

Defining an Attribute Class

To create a custom attribute, you must define an attribute class derived from the base class Attribute . By convention, you give your class a name ending in "Attribute." The name of your class without the "Attribute" suffix will be the name of the custom attribute. In our example the class name is InitialDirectoryAttribute , so the attribute's name is InitialDirectory .

You may provide one or more constructors for your attribute class. The constructors define how to pass positional parameters to the attribute (provide a parameter list, separated by commas). It is also possible to provide "named parameters" for a custom attribute, where the parameter information will be passed using the syntax name = value.

You may also provide properties to read the parameter information. In our example, we have a property Path , which is initialized in the constructor.

  <AttributeUsage(AttributeTargets.Class)> _   Public Class InitialDirectoryAttribute  Inherits Attribute     Private m_Path As String     Public Sub New(ByVal path As String)         Me.m_Path = path     End Sub     Public ReadOnly Property Path() As String         Get             Return m_Path         End Get     End Property End Class 

Defining a Base Class

The last step in working with a custom attribute is to provide a means to extract the custom attribute information from the metadata, using the reflection classes. You can obtain the Type of any object by calling the method GetType , which is provided in the root class Object . Using the class's method GetCustomAttributes , you can read the custom attribute information.

To make the coding of the client program as simple as possible, it is often useful to provide a base class that does the work of reading the custom attribute information. [10] We provide a base class DirectoryContext , which is used by a class wishing to take advantage of the InitialDirectory attribute. This base class provides the property DirectoryPath to return the path information stored in the metadata. Here is the code for the base class:

[10] With single implementation inheritance, there is a cost to providing a base class. If you need to derive from another class, such as ContextBoundObject , the base class has to derive from that class.

 ' DirectoryContext.cs Imports System  Imports System.Reflection  Imports System.IO Public Class  DirectoryContext  Public Overridable ReadOnly Property  DirectoryPath  () _     As String       Get  Dim t As Type = Me.GetType()   Dim a As Attribute   For Each a In t.GetCustomAttributes(True)   Dim da As InitialDirectoryAttribute =  a  If Not da Is Nothing Then   Return da.Path  End If           Next           Return Directory.GetCurrentDirectory()        End Get    End Property End Class 

We must import the System.Reflection namespace. GetType returns the current Type object, and we can then use the GetCustomAttributes method can obtain a collection of Attribute objects from the metadata. Since this collection is heterogeneous, consisting of different types, the result of the VB.NET assignment operator is tested against Nothing in an If statement. This is used to test if a given collection element is of the type InitialDirecto ryAttribute . If we find such an element, we return the Path property. Otherwise, we return the default current directory, obtained from GetCurrentDirectory .


Team-Fly    
Top
 


Application Development Using Visual BasicR and .NET
Application Development Using Visual BasicR and .NET
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 190

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net