Attributes

Team-Fly    

 
Application Development Using Visual Basic and .NET
By Robert J. Oberg, Peter Thorsteinson, Dana L. Wyatt
Table of Contents
Chapter 6.  VB.NET in the .NET Framework


A modern approach to implementing complex code is to let the system do it for you. There must be a way for the programmer to inform the system of what is desired. In the .NET Framework such cues can be given to the system by means of attributes .

Microsoft introduced attribute-based programming in Microsoft Transaction Server (MTS). The concept was that MTS, not the programmer, would implement complex tasks such as distributed transactions. The programmer would "declare" the transaction requirements for a COM class, and MTS would implement it. This use of attributes was greatly extended in the next generation of MTS, known as COM+. In MTS and COM+ attributes are stored in a separate repository, distinct from the program itself.

Attributes are also used in Interface Definition Language (IDL), which gives a precise specification of COM interfaces, including method signatures and parameter marshaling. Part of the function of IDL is to make it possible for a tool to generate proxies and stubs for remoting a method call across a process boundary or even across a network. When parameters are passed remotely, it is necessary to give more information than when they are passed within the same process. For example, within a process, you can simply pass a reference to an array. But in passing an array across a process boundary, you must inform the tool of the size of the array. This information is communicated in IDL by means of attributes, which are specified using a square- bracket notation. Here is an example of IDL that shows the use of attributes.

 [    object,    uuid(AAA19CDE-C091-47BF-8C96-C80A00989796),    dual,    pointer_default(unique) ] interface IAccount : IDispatch {    [id(1)] HRESULT Deposit([in] long id, [in] long amount);    [id(2)] HRESULT Withdraw([in] long id, [in] long amount);    [id(3)] HRESULT GetBalance([in] long id,               [out] long *pBal);    [id(4)] HRESULT GetAllBalances([in, out] long* pCount,               [out, size_is(*pCount)] long balances[]); }; 

If you are experienced with COM, such IDL will be familiar to you. If not, just notice the general structure of how attributes are used. Attributes such as object and uuid are applied to the interface, the id attribute is applied to methods , and the attributes in , out , and size_is are applied to parameters.

A problem with attributes in both MTS/COM+ and IDL is that they are separate from the program source code. When the source code is modified, the attribute information may get out of sync with the code.

Attributes in .NET

In .NET, attributes are declared with angle brackets, unlike IDL. Also unlike IDL, the attributes are part of the program source code. When compiled into intermediate language, the attributes become part of the metadata. There are some predefined attributes in VB.NET, there are many attributes associated with various .NET classes, and there is a mechanism to create custom attributes for your own classes. In this section we look at the general characteristics of how attributes are used, beginning with a simple example of using one of the predefined attributes in VB.NET. In later chapters attributes associated with specific .NET classes will be used extensively, and in Chapter 10, after we've discussed Reflection, we will see how to create and use custom attributes.

The AttributeDemo program provides a simple example of using the predefined VB.NET attribute Conditional , which is used to mark a method to be executed only if a preprocessor symbol is defined.

 graphics/codeexample.gif ' AttributeDemo.vb  #Const LINUX = True  '#Const UNIX = True Imports System  Imports System.Diagnostics  Module AttributeDemo    Sub Main()       Notice()       MultiNotice()       Console.WriteLine("Goodbye")    End Sub  <Conditional("UNIX")>  _    Private Sub Notice()       Console.WriteLine("Notice: Unix version")    End Sub  <Conditional("UNIX"), Conditional("LINUX")>  _    Private Sub MultiNotice()       Console.WriteLine("Notice: Some version of Unix")    End Sub End Module 

Conditional is one of three predefined attributes in VB.NET. [8] Its full name is ConditionalAttribute , but VB.NET has the convenience feature that when an attribute's name ends with the Attribute suffix, you may drop the suffix. Conditional is used to mark a method with a symbol. If that symbol is defined by the preprocessor, calls to the method will be included; otherwise , calls will be omitted. The Conditional attribute is multiuse, which means that it may be used several times in front of a method. For example, in the code above the MultiNotice method is conditioned on either UNIX or LINUX, and calls to this method will be included if either symbol is defined. The preprocessor #Const directive [9] defines the symbol LINUX. The UNIX symbol is commented out, so it is not defined (unless done via a compiler option, which we'll look at shortly). The Conditional attribute requires the namespace System.Diagnostics . (We will discuss .NET diagnostic support in detail in Appendix B.)

[8] The other two predefined attributes in VB.NET are Obsolete and AttributeUsage . Obsolete is used to mark a program entity that should not be used, causing the compiler to issue a warning or error message if it is used. We will discuss AttributeUsage in Chapter 10 in connection with custom attributes.

[9] VB.NET (unlike C, C++, and C#) does not allow the use of the #define preprocessor directives to define macros.

Running the program produces the following output:

 Notice: Some version of Unix Goodbye 

The call to Notice is omitted, but the call to MultiNotice is included. You may experiment with this program by defining the symbol UNIX (you can just uncomment it), or define no symbols, and so on. Then run the program again and to see which what code executes.

Preprocessor Symbols Using Compiler Option

Besides using a #Const preprocessor directive in your source code, you can also define preprocessor symbols using the /define command-line option of the VB.NET compiler. For example, you can define the symbol UNIX using the following command:

 vbc /define:UNIX=True AttributeDemo.vb 

You can also specify preprocessor directives in Visual Studio. In Solution Explorer right-click on the project node. From the context menu choose Properties. Select Build from Configuration Properties, and enter your desired string (such as UNIX=True) in the Custom constants text field, as illustrated in Figure 6-5.

Figure 6-5. Specifying a preprocessor symbol in Visual Studio.

graphics/06fig05.jpg

Using Attributes

The AttributeDemo example demonstrated an attribute with a single String parameter. Attributes can take multiple parameters, and there can also be named parameters. Named parameters are useful when there are many different parameters, and in a particular case you might use only some of them. Named parameters can appear in any order.

As an example, the DllImport attribute takes a single positional parameter (the name of the DLL) and several named parameters. Here is an example [10] of using the DllImport attribute, with named parameters CharSet and CallingConvention:

[10] This is not in any example code provided for this chapter; however, see Chapter 17.

 <DllImport("KERNEL32.DLL", CharSet:=CharSet.Unicode, CallingConvention:=CallingConvention.StdCall)> 

We will see examples of the use of DllImport in Chapter 17, when we discuss the Platform Invocation Service (or PInvoke), which enables you to call unmanaged code through functions implemented in a DLL.

Attribute Targets

An attribute may be applicable to different kinds of entities. In the COM IDL example we saw examples of attributes for interfaces, methods, and parameters. In .NET attributes may be applied to many different kinds of entities, including

  • assembly

  • module

  • class

  • struct

  • interface

  • method

  • parameter

There are many more. The specification of legal entities to which an attribute may be applied is part of the definition of an attribute, and you will get a compiler error message if you attempt to use an attribute on the wrong kind of entity. When we discuss custom attributes in Chapter 10, we will see how to specify the legal attribute targets for our own attributes.


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