Understanding the Role of Attributes

Team-Fly    

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

Understanding the Role of Attributes

Attributes are used to add metadata to an assembly. From the introduction we know that attributes provide information such as the vendor or author information, but attributes provide much more.

Attributes describe how data is serializedwritten as a stream of bytes for transmission, security models, limiting optimizations for the Just-In-Time compiler (or JITter), and runtime behavior. This section examines the role of attributes, demonstrating how these different uses for attributes are applied.

What Is Metadata?

Metadata is binary data that describes your application. The metadata can be stored in memory or as part of a portable executable (PE).

Metadata describes the elements of your application in a multilanguage format. This allows a JIT compiler that can read the assembly metadata to translate the multilanguage information into an executable for a specific platform.

Microsoft believes that metadata is essentially a simpler application building model. Metadata accomplishes the following:

  • Eliminates the need for separate Interface Definition Language (IDL) files

  • Combines definition and implementation into a single file

  • Ensures that files are self-describing

  • Enables custom attributes, thus providing extensibility

Metadata Eliminates IDL Files

IDL is that cryptic language used to define interfaces in support of COM. Listing 12.1 contains the IDL code for ATL.IDL, the Abstract Template Library IDL file. (Don't worryyou will not need to fully understand or work with this file.)

Listing 12.1 An example of IDL code from ATL.IDL
 #include <olectl.h> // atl.idl : IDL source for atl.dll // // This file will be processed by the MIDL tool to // produce the type library (atl.tlb) and marshalling code. import "oaidl.idl"; import "atliface.idl"; import  "ocidl.idl"; [     uuid(44EC0535-400F-11D0-9DCD-00A0C90391D3),     version(1.0),     helpstring("ATL 2.0 Type Library") ] library ATLLib {     importlib("stdole32.tlb");     importlib("stdole2.tlb");     interface IDocHostUIHandlerDispatch;     interface IAxWinAmbientDispatch; }; 

Fortunately, as Visual Basic developers we never had to worry much about IDL and in .NET, metadata eliminates the need for it.

Metadata Combines Definition and Implementation

Listing 12.1 contains references to other .idl files as well as an olectl.h file. Files with a .h extension are C++ header files. The C++ programming language uses .h files to describe classes and .cpp files to implement those classes.

The need for separate definition and implementation files has been eliminated by metadata. This benefit will be less noticeable to VB developers but represents one of the problems metadata redresses.

Metadata Makes Assemblies Self-Describing

Metadata makes assemblies self-describing in a multilanguage way. The benefit of this capability is that the additional information travels with the executable, and the multilanguage implementation of the metadata allows for seamless integration between assemblies written in disparate .NET languages.

Listing 12.2 demonstrates the seamlessness of .NET languages. This listing shows two modules from separate assemblies. One is a class library implemented in C# (C Sharp), and the other is a simple Windows application written in Visual Basic .NET.

Listing 12.2 Two modules from separate assemblies, each implemented in a different .NET language
  1:  ' C# Module  2:  using System;  3:   4:  namespace CSharpLibrary  5:  {  6:  /// <summary>  7:  /// Summary description for Class1.  8:  /// </summary>  9:  public class MyMath  10:  {  11:  static public double Add(double lhs, double rhs)  12:  {  13:  return lhs + rhs;  14:  }  15:  }  16:  }  17:   18:  ' VB .NET Module  19:  Public Class Form1  20:  Inherits System.Windows.Forms.Form  21:   22:  [ Windows Form Designer generated code ]  23:   24:  Private Function DoConvertError(ByVal E As Exception, _  25:  ByVal Control As TextBox)  26:   27:  Const Message As String = _  28:  "'{0} ' cannot is not a valid number"  29:  MsgBox(String.Format(Message, Control.Text), MsgBoxStyle.Exclamation)  30:  Control.Focus()  31:  Throw E  32:  End Function  33:   34:  Private Function ToDouble(ByVal Control As TextBox) As Double  35:  Try  36:  Return CDbl(Control.Text)  37:  Catch E As InvalidCastException  38:  DoConvertError(E, Control)  39:  End Try  40:  End Function  41:   42:  Private ReadOnly Property LeftHandSide() As Double  43:  Get  44:  Return ToDouble(TextBox1)  45:  End Get  46:  End Property  47:   48:  Private ReadOnly Property RightHandSide() As Double  49:  Get  50:  Return ToDouble(TextBox2)  51:  End Get  52:  End Property  53:   54:  Private Sub UpdateSum()  55:  Try  56:  TextBox3.Text = _  57:  CSharpLibrary.MyMath.Add(LeftHandSide, RightHandSide)  58:  Catch  59:  End Try  60:  End Sub  61:   62:  Private Sub Button1_Click(ByVal sender As System.Object, _  63:  ByVal e As System.EventArgs) Handles Button1.Click  64:  UpdateSum()  65:  End Sub  66:  End Class 

The first 16 lines hold the code from the .cs (C#) module extracted from the class library implemented in C#. The rest of the code is from a .vb module excerpted from the Windows application implemented in Visual Basic .NET. The example is quite straightforward. The Windows application accepts two doubles and returns the sum of the two doubles by calling the staticequivalent to shared in Visual Basic .NETmethod Add on line 57, in the C# class library.

Both of the projects reside in the same solution (on the www.samspublishing.com Web site). VS .NET allows you to easily step from the Visual Basic .NET code right into the C# code and back without any special effort.

Previously, if you wanted to use DLLs implemented in other languages, you had to be intimately aware of the language the library was implemented in, how to load those libraries, and what the calling convention of the library's language was. For instance, you had to know if the arguments to methods were called in reverse order or in order and indicate this knowledge by using calling convention specifiers like cdecl . Even if you knew intimate details about the external library, it was often difficult if not impossible to trace from your application into the source code of the library.

The .NET world allows you to reference an assembly, import the namespace of interest, and go. You can step into and out of code implemented in various .NET languages, as well as use object-oriented idioms between languages. For example, a Visual Basic .NET class can inherit from a C# class or implement an interface defined in C# and vice versa.

This interchangeability between .NET languages, the similarities between languages, and commonality of the CLR are reasons that Microsoft says that the language you choose is more of a lifestyle choice than a technical choice, at least as far as .NET is concerned . Technically, you could hire C# and Visual Basic .NET developers and have them work on the same project quite easily. The class listing in Listing 12.3 demonstrates a revision to the earlier code. The MyMath class is subclassed and extended in the VB .NET code.

Listing 12.3 A VB .NET class that subclasses and extends a C# class, all facilitated by metadata
  1:  Public Class VBMyMath  2:  Inherits CSharpLibrary.MyMath  3:   4:  Public Shared Function Divide(_  5:  ByVal lhs As Double, ByVal rhs As Double) As Double  6:  Return Decimal.op_Division(lhs, rhs)  7:  End Function  8:   9:  End Class 

Note that the code listing is VB .NET code. Clearly the VBMyMath class inherits CSharpLibrary.MyMath. The VBMyMath class extends the C# class by adding a divide method.

Note

The long form of division Decimal.op_Division was used instead of the / operator to point out that methods that performed the operation existed also. It is not especially relevant to the discussion.


VBMyMath contains two shared methods now: Add and Divide. Just for fun, some additional oddities were implemented. Listing 12.4 contains a revised listing to the Windows application to illustrate some of the advanced idioms available in VB .NET code.

Listing 12.4 Language aerobics
  1:  Public Class Form1  2:  Inherits System.Windows.Forms.Form  3:   4:  [ Windows Form Designer generated code ]  5:   6:  Private Function DoConvertError(ByVal E As Exception, _  7:  ByVal Control As TextBox)  8:   9:  Const Message As String = _  10:  "'{0} ' cannot is not a valid number"  11:  MsgBox(String.Format(Message, Control.Text), MsgBoxStyle.Exclamation)  12:  Control.Focus()  13:  Throw E  14:  End Function  15:   16:  Private Function ToDouble(ByVal Control As TextBox) As Double  17:  Try  18:  Return CDbl(Control.Text)  19:  Catch E As InvalidCastException  20:  DoConvertError(E, Control)  21:  End Try  22:  End Function  23:   24:  Private ReadOnly Property LeftHandSide() As Double  25:  Get  26:  Return ToDouble(TextBox1)  27:  End Get  28:  End Property  29:   30:  Private ReadOnly Property RightHandSide() As Double  31:  Get  32:  Return ToDouble(TextBox2)  33:  End Get  34:  End Property  35:   36:  Private Overloads Sub UpdateSum()  37:  Try  38:  TextBox3.Text = _  39:  CSharpLibrary.MyMath.Add(LeftHandSide, RightHandSide)  40:  Catch  41:  End Try  42:  End Sub  43:   44:  ' Just for fun!  45:  Private Delegate Function Procedure(ByVal lhs As Double, _  46:  ByVal rhs As Double) As Double  47:   48:  Private Overloads Sub UpdateSum(ByVal Proc As Procedure)  49:  Try  50:  TextBox3.Text = Proc(LeftHandSide, RightHandSide)  51:  Catch  52:  End Try  53:  End Sub  54:   55:  Private Sub Button1_Click(ByVal sender As System.Object, _  56:  ByVal e As System.EventArgs) Handles Button1.Click  57:   58:  UpdateSum(AddressOf VBMyMath.Add)  59:   60:  End Sub  61:   62:  Private Sub Button2_Click(ByVal sender As System.Object, _  63:  ByVal e As System.EventArgs) Handles Button2.Click  64:  UpdateSum(AddressOf VBMyMath.Divide)  65:  End Sub  66:  End Class 

Note

Listing 12.4 demonstrates some advanced idioms for fun. Clearly we would not write production code to perform arithmetic like this, but the listing does illustrate the newfound expressiveness in Visual Basic that previously was only available in C++ and Object Pascal.

Download MultilanguageDemo.sln from the www.samspublishing.com Web site, or create a Windows Application and add three textbox controls and two buttons to the default form.


The listing introduces a Delegate on lines 45 and 46. Instances of the delegate will contain functions that take two doubles and return a double. Using the Delegate, we can overload the UpdateSum method to accept an argument of type Procedure, the name of the Delegate. The overloaded version is defined on lines 48 through 53. The new UpdateSum looks almost identical to the old UpdateSum except for the addition of the Delegate argument and the fact that the Delegate argument is used to invoke the behavior. Finally the two button-click events invoke the Add or Divide behavior.

It is interesting to note that we are able to leverage the error-handling and field-handling code for the TextBox controls and had to write very little GUI code using these highly refactored methods.

Attributes Support Extensibility

Attributes support extensibility. Attribute is a class in the CLR that can be inherited from and extended. Because attributes provide you with a way to add additional metadata, you can extend and customize the IDE using attributes. (Refer to the section "Creating Custom Attributes" later in this chapter for examples.)

Attribute Naming

Attributes are classes. By convention they are named with the word Attribute attached as a suffix. Attributes are applied using a special metatag notation and do not require the full name when applied.

Attribute tags generally have a syntax that looks similar to a method call where the attribute name is the method and you pass any parameters needed by the attribute in parentheses. Attribute tags are placed before the method inside metatag brackets <>. The following syntax example demonstrates attribute usage in general:

 <  attributename  ([  args0,   args1..   argsn  ])> ProcedureHeader 

AttributeName is the name of the attribute with or without the Attribute suffix. Attribute constructors can be overloaded, allowing you to select the specific overloaded version and pass the arguments you need to.

A single example of an attribute class is System.ObsoleteAttribute. The Obsolete attribute can be used to mark obsolete code that you might intend to remove in future versions of your application. You can look up the ObsoleteAttribute class and find out information about its constructors, properties, and methods in the help file.

There are three versions of the ObsoleteAttribute.New method. One version accepts a message string and a Boolean indicating whether using the method will cause a compiler error or not. Let's revisit Listing 12.4. Suppose that we want to encourage users of the code not to call the old UpdateSum method on line 36; we would rather have them use the new version that takes a Delegate. We could mark the old UpdateSum method with the Obsolete tag, discouraging developers from using it. Listing 12.5 demonstrates the technical aspects.

Listing 12.5 System.ObsoleteAttribute demonstrates the technical application of attributes
 <Obsolete("This method is going to be removed", True)> _ Private Overloads Sub UpdateSum()   Try     TextBox3.Text = _       CSharpLibrary.MyMath.Add(LeftHandSide, RightHandSide)   Catch   End Try End Sub 

The excerpt from Listing 12.4 has been modified to use the Obsolete attribute. When the application is compiled, a compiler error will be indicated displaying the text message "This method is going to be removed". If we had passed False, the application would compile without a failure because of the Obsolete attribute.

Things That Attributes Describe

Attributes are used to describe a wide variety of things. Attributes describe how data is serialized, specify assembly security, limit JIT compiler optimizations, control the visibility of members , prevent the debugger from stepping into specific methods, and define runtime behavior.

Because attributes are an extensible part of VS .NET, you will discover that the pool of attributes will grow over time.

Describing an Assembly

A common use for attributes is to describe the assembly. These attributes are assembly-level attributes and are placed in the assemblyinfo.vb file and tagged with the Assembly keyword.

Assembly attributes provide Title, Description, Company, Product, Copyright, Trademark, and CLS compliance information. You will also find version information and a GUID that is used in case the assembly is exposed to COM, such as an add-in.

To modify attributes providing assembly information, open the assemblyinfo.vb file from the Solution Explorer and enter the assembly-level information using the code editor. Listing 12.6 contains the assemblyinfo.vb file from the MultilanguageDemo.vbproj project.

Listing 12.6 A typical assemblyinfo.vb file containing assembly-level information
  1:  Imports System.Reflection  2:  Imports System.Runtime.InteropServices  3:   4:  ' General Information about an assembly  5:  ' is controlled through the following  6:  ' set of attributes. Change these attribute  7:  ' values to modify the information  8:  ' associated with an assembly.  9:   10:  ' Review the values of the assembly attributes  11:   12:  <Assembly: AssemblyTitle("")>  13:  <Assembly: AssemblyDescription("")>  14:  <Assembly: AssemblyCompany("")>  15:  <Assembly: AssemblyProduct("")>  16:  <Assembly: AssemblyCopyright("")>  17:  <Assembly: AssemblyTrademark("")>  18:  <Assembly: CLSCompliant(True)>  19:   20:  'The following GUID is for the ID of the  21:  'typelib if this project is exposed to COM  22:  <Assembly: Guid("A5AC547D-3C13-4C7F-A917-BE076B3331C6")>  23:   24:  ' Version information for an assembly  25:  ' consists of the following four values:  26:  '  27:  '      Major Version  28:  '      Minor Version  29:  '      Build Number  30:  '      Revision  31:  '  32:  ' You can specify all the values or you  33:  ' can default the Build and Revision Numbers  34:  ' by using the '*' as shown below:  35:   36:  <Assembly: AssemblyVersion("1.0.*")> 

Using the code editor, we can type in a view-friendly application title between the double quotation marks after AssemblyTitle. The same is true for each of the attributes describing the assembly.

Assembly attributes are also referred to as global attributes. There are four categories of global attributes, including: identity attributes, information attributes, manifest attributes, and strong name attributes. The categories of attributes are briefly described in the subsections that follow.

Identity Attributes

The identity attributes are AssemblyVersionAttribute, AssemblyCultureAttribute, and AssemblyFlagsAttribute. Listing 12.6 demonstrates the AssemblyVersionAttribute. (Recall that the full class name is not required and not used by convention. This yields the actual application of the attribute as AssemblyVersion.)

Identity and strong name attributes uniquely identify an assembly. This is an evolutionary distinction from earlier versions where the filename was used to distinguish one application from another.

Informational Attributes

Informational attributes are used to provide About information, who you and your company are and what your product is all about. These attributes are

AssemblyProductAttribute

AssemblyTrademarkAttribute

AssemblyInformationalVersionAttribute

AssemblyCompanyAttribute

AssemblyCopyrightAttribute

AssemblyFileVersionAttribute

You can find examples of these attributes in Listing 12.6.

Manifest Attributes

Assembly manifest attributes are used to provide information in the assembly's manifest. Manifest attributes provide title, description, configuration, and default alias information. These attributes are: AssemblyTitleAttribute, DescriptionAttribute, ConfigurationAttribute, and DefaultAliasAttribute.

To view manifest information, use the ildasm.exe application that ships with the framework SDK.

Strong Name Attributes

Strong name attributes define the strong name key file, which is used in conjunction with identity attributes to uniquely identify assemblies. Strong name attributes are: AssemblyDelaySignAttribute, AssemblyKeyFileAttribute, and AssemblyKeyNameAttribute.


Team-Fly    
Top
 


Visual BasicR. NET Unleashed
Visual BasicR. NET Unleashed
ISBN: N/A
EAN: N/A
Year: 2001
Pages: 222

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