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:
Metadata Eliminates IDL FilesIDL 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 ImplementationListing 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-DescribingMetadata 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 language1: ' 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 metadata1: 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 aerobics1: 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 ExtensibilityAttributes 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 NamingAttributes 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 DescribeAttributes 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 AssemblyA 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 information1: 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 AttributesThe 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 AttributesInformational attributes are used to provide About information, who you and your company are and what your product is all about. These attributes are
You can find examples of these attributes in Listing 12.6. Manifest AttributesAssembly 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 AttributesStrong 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 |