Attributes

for RuBoard

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. 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 the methods and signatures. 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 square brackets, as in IDL. But 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 C#, 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 C#. In later chapters attributes associated with specific .NET classes will be used extensively, and in Chapter 8, 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 C# attribute Conditional , which is used to mark a method to be executed only if a preprocessor symbol is defined.

 // AttributeDemo.cs  #define LINUX  using System;  using System.Diagnostics;  public class AttributeDemo  {     public static void Main(string[] args)     {        Notice();        MultiNotice();        Console.WriteLine("Goodbye");     }  [ConditionalAttribute("UNIX")]  private static void Notice()     {        Console.WriteLine("Notice: Unix version");     }  [Conditional("UNIX")] [Conditional("LINUX")]  private static void MultiNotice()     {        Console.WriteLine("Notice: Some version of Unix");     }  } 

Conditional is one of three predefined attributes in C#. [8] Its full name is ConditionalAttribute , but C# 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 #define directive [9] defines cthe symbol "LINUX." The "UNIX" symbol 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 Chapter 13.)

[8] The other two predefined attributes in C# 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 8 in connection with custom attributes.

[9] C#, unlike C and C++, does not allow use of 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 no symbols, defining "UNIX," etc.

Preprocessor Symbols Using Compiler Option

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

 csc /define:UNIX AttributeDemo.cs 

You can also specify preprocessor directives in Visual Studio. In Solution Explorer right-click on the solution. From the context menu choose Properties. Select Build from Configuration Properties, and enter your desired string in the Conditional Compilation Constant section, as illustrated in Figure 5-5.

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

graphics/05fig06.gif

Using Attributes

The example program 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 may 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 positional parameters. Here is an example of using the DllImport attribute, with named parameters CharSet and CallingConvention :

 [DllImport("KERNEL32.DLL", CharSet=CharSet.Unicode,  CallingConvention=CallingConvention.StdCall)] 

We will see examples of the use of DllImport in Chapter 14, 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

and 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 8, we will see how to specify the legal attribute targets for our own attributes.

for RuBoard


Application Development Using C# and .NET
Application Development Using C# and .NET
ISBN: 013093383X
EAN: 2147483647
Year: 2001
Pages: 158

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