2.8 The Global Assembly Cache

only for RuBoard

2.8 The Global Assembly Cache

If you use an object from the .NET class library in your own code, you have to reference the assembly in which it is defined at compile time. For instance, if you want to use the MessageBox class in one of your applications, you need to make sure that the System.Windows.Forms assembly is made available to the compiler. This assembly contains the System.Windows.Forms namespace, which in turn contains the MessageBox class. The command-line statement needed to compile your source code is:

 vbc /t:winexe /r:System.Windows.Forms.dll mycode.vb 

Referencing one of your own assemblies is no different, but a full path to the assembly is expected. For example:

 vbc /t:library /r:<path>\mylib.dll mycode.vb 

A path is not necessary for System.Windows.Forms.dll because like all .NET class library assemblies, it lives in the global assembly cache (GAC). The GAC is a directory, shown in Figure 2-5, that contains assemblies that are meant to be shared by several applications on a single machine. The actual path to the GAC is <%windir%>/assembly .

Figure 2-5. The GAC in an Explorer list pane
figs/oop_0205.gif

2.8.1 Strong Names

If you want to share an assembly by putting it in the GAC, it must have a strong name . A strong name defines the assembly's identity: its name, version number, and culture information (if it exists), a public key, and a digital signature.

2.8.1.1 Strong Name utility

The first step toward giving an assembly a strong name is creating a key pair file that contains the public/private keys used to sign the assembly. To create the key pair file, use the Strong Name tool from the command line:

 sn -k hello.snk 

Doing so creates a key pair file named hello.snk .

2.8.1.2 Assembly Linker

Next, you need to use the Assembly Linker (AL) to sign the assembly with the key pair file. This utility is not specific to any language, so you can't feed it source code. You do need to compile your library to a module first, using a command line like the following:

 vbc /t:module hello.vb 

Compiling your library produces a module called hello.netmodule . Now you can use AL to create a signed assembly like this:

 al /out:hello.dll hello.netmodule /keyfile:hello.snk 

The result is a signed assembly with the name hello.dll .

2.8.1.3 Gacutil

Now that you have a signed assembly, you can use the Global Assembly Cache tool, gacutil.exe , to install it to the GAC, as shown in the following command:

 gacutil /i hello.dll 
only for RuBoard
only for RuBoard

2.9 System Namespace

Every time you compile anything in Visual Basic, the compiler automatically references two assemblies: mscorlib.dll and Microsoft.VisualBasic.dll . These two components contain the System and Microsoft.VisualBasic namespaces, respectively (a small portion of the System namespace is also contained in System.dll ).

The System namespace is the root namespace of primary types in .NET and contains the base data types used by all languages in the framework. When you declare a primitive data type in VB, it is actually mapped to a type defined in this namespace. Table 2-1 provides a list of the types in System and how they relate to Visual Basic.

Table 2-1. Data type mappings from System to VB

System

Visual Basic

Description

Byte

Byte

8-bit unsigned integer

Int16

Short

16-bit signed integer

Int32

Integer

32-bit signed integer

Int64

Long

64-bit signed integer

Single

Single

32-bit floating point

Double

Double

64-bit floating point

Boolean

Boolean

True or False

Char

Char

Unicode character

Decimal

Decimal

96-bit decimal value

String

String

Unicode character string

Object

Object

Base of all objects

How you declare variables in your code doesn't matter. Each represents a functional equivalent:

 Dim x As System.Int32
'Is the same as
Dim x As Integer 

If you examine Table 2-1 you will see that the Byte is the only unsigned data type supported by VB. All other integer types are signed. The Common Language Specification doesn't support unsigned integers larger than 8 bits, but they do exist in the framework (see Table 2-2). They can be used freely , provided you understand that the code you write might not be CLS-compliant.

Table 2-2. Non-CLS-compliant types

Class

Description

SByte

8-bit signed integer

UInt16

16-bit unsigned integer

UInt32

32-bit unsigned integer

UInt64

64-bit unsigned integer

You can always call GetType to get the underlying type:

 Console.WriteLine(GetType(Integer)) 

This code returns " System.Int32 ".

It is OK to use non-CLS-compliant types internally within your classes and still produce CLS-compliant objects. However, methods that are exposed to the outside world should not contain non-CLS-compliant types as parameters. Keep this in mind if it is important for your objects to be accessible to everyone.

In addition to defining core data types, the System namespace contains classes that provide a wide variety of services:

  • Data type conversion

  • Mathematical functionality

  • Exception handling

  • Remote and local program invocation

  • Garbage collection

It also contains secondary and tertiary namespaces that compose the rest of the .NET class library.

2.9.1 The Microsoft.VisualBasic Namespace

The Microsoft.VisualBasic namespace contains all that can be considered classic Visual Basic. It contains all the functionality that has been with the language before its evolution into object orientation.

String functions such as Left , Right , and Mid are in this namespace. They are members of the Strings class. The FileSystem class makes traditional file I/O using Open , Input , and Write available. Array validation functions like LBound and UBound are available through the Information class. Notification functions like MsgBox , InputBox , and even Beep are available via the Interaction class.

These methods are all defined with Public Shared access, which means you don't need specific instances of Strings , Information , or Interaction to call these functions. Public Shared access is similar to declarations using the static keyword in C++, C#, and Java. You can access the members of these classes directly, so your code still has the look and feel of traditional Visual Basic (which looks more procedural).

Example 2-5 shows a simple Visual Basic program that takes a phone number as a command-line argument. The program adds up the digits that correspond to the phone number and returns the value in the console window. The example uses functionality strictly found in the Microsoft.VisualBasic namespace. Examine the code carefully . In a moment, we'll look at the same program rewritten using only classes from the System namespace.

Example 2-5. A phone in VB
 Option Strict On
   
Imports System
Imports Microsoft.VisualBasic
   
Public Class Application
   
  Public Shared Sub Main( )
   
    Dim i As Integer
    Dim digit As String
    Dim total As Double
   
    'Get phone number from command line
    Dim phoneNumber As String = Command( )
   
    If Len(phoneNumber) > 0 Then
      For i = 1 To Len(phoneNumber)
        'Get each digit 
        digit = Mid(phoneNumber, i, 1)
        If IsNumeric(digit) Then
          total += Val(digit)
        End If
      Next i
      Console.WriteLine("Your phone number totals: " & total)
    End If
   
    Console.WriteLine("Press ENTER to continue...")
    Console.ReadLine( )
   
  End Sub
   
End Class 

In Example 2-5, the phone number is retrieved using Command , which retrieves command-line arguments, but unfortunately does not provide us with a means to specify which argument we are interested in. Fortunately, there is only one argument in this example ( assuming that there are no spaces in the input). The string representing the phone number is then searched, one character at a time, by using Mid . If a character represents a numerical value, then it is converted to a Byte by calling Val , and the result is added to the total. The total is then displayed in the console window.

If you save Example 2-5 to a file named phone.vb , you can compile it into an executable using the /t:exe compiler option as follows :

 C:>vbc /t:exe /optionstrict+ phone.vb 

This compilation produces an executable named phone.exe , which you can run from the command line like this:

 C:>phone (713)555-1212
Your phone number totals: 32 

You can replace the Console.WriteLine call in Example 2-5 with a call to MsgBox to display the result in a message box:

 MsgBox("Your phone number totals: " & total) 

However, you need to compile the example to a Windows executable by using the winexe target option:

 C:>vbc /t:winexe phone.vb 

2.9.2 The .NET Class Library

It could be argued that much of the functionality that exists in Microsoft.VisualBasic is not a part of the Visual Basic language, but merely tied to it by heritage.

Consider the C runtime library. It contains functions that have been used by C programmers for years . The function used to output a message to the console, printf , has been used in millions of lines of code since the dawn of time, which we all know began on January 1, 1970. However, this function is not part of the C language proper. It is defined in a file called stdio.h . As a C programmer, you could write your own printf function to replace the one in the runtime library. Doing so is not practical, but you can still do it because it is not a part of the language specification.

Most, if not all, functionality provided by Microsoft.VisualBasic is available through the .NET class library. An argument that can be made against using Microsoft.VisualBasic is that programmers using other languages will have a difficult time understanding this code. People using other languages to develop for the .NET platform will use the .NET class library extensively and will probably not use anything from Microsoft.VisualBasic . It sounds strange to say this in a book about Visual Basic, but if you are a newcomer to VB, this is something you might want to consider. Learning everything in both namespaces will be like learning two languages at once instead of onea daunting task, to say the least.

Conversely, if you have experience with Visual Basic, this issue will not affect you. The Microsoft.VisualBasic namespace is targeted toward you, and its primary purpose is to provide the functionality that was part of the language since its inception. You can use what you know and love and get all the benefits of the .NET platform. However, you should still learn as much as you can about the .NET class library and start incorporating that knowledge into your future projects.

To get another perspective on this issue, look at Example 2-5, which is rewritten in Example 2-6 to use only the .NET class library. Note that the code's atmosphere is completely different. Using classes from the Microsoft.VisualBasic namespace will give your code an almost procedural look at times. In contrast, using functionality from the other namespaces of the .NET class library results in code that is less procedural and more object-oriented. "Is it Visual Basic?" you ask. The answer to this question is simple. Yes, of course it is.

Example 2-6. Phone in .NET
 Imports System
   
Public Class Application
   
  Public Shared Sub Main(ByVal args( ) As String)
   
    Dim c As Char
    Dim total As Integer
   
    If args.Length = 0 Then
      Return
    End If
   
    'Get phone number from command line
    Dim digits( ) As Char = args(0).ToCharArray( )
   
    For Each c In digits
      If Char.IsDigit(c) Then
        total += Convert.ToInt32(c.ToString( ))
      End If
    Next c
   
    Console.WriteLine("Your phone number totals: {0}", _
                      total.ToString( ))
    Console.WriteLine("Press ENTER to continue...")
    Console.ReadLine( )
  End Sub
   
End Class 

Example 2-5 and Example 2-6 do exactly the same thing. They are both Visual Basic, but stylistically they are completely different. Save this code to phone.net.vb and compile it.

In this example, you get the digits of the phone number from the command line through the Environment class instead of the Command method. In this case, you can specify which argument you want and convert the result directly to an array of characters . Then you can traverse the array easily by using the For...Each language syntax. The Char data type provides a shared method called IsDigit that lets you determine whether you are dealing with a numeric value. If so, the Convert class converts the character to a Byte , and the result is added to the total.

Almost everything in the two listings is completely different. Even the seemingly innocuous call to Console.WriteLine was modified. In Example 2-5, it looked like this:

 Console.WriteLine("Your phone number totals: " & total) 

Here, total is implicitly converted to a string and then concatenated to the output message.

In Example 2-6, the call looks like this:

 Console.WriteLine("Your phone number totals: {0}", total.ToString( )) 

In this case, a format specification {0} is replaced with the value of total when the output message is displayed. Also, total is explicitly converted to a String .

After comparing Example 2-5 and Example 2-6 side by side, can you say that one method is better than the other? No, not really. It's all a matter of preference and style. Aspects of each listing are appealing. As a Visual Basic programmer, you will probably initially use functionality from both System and Microsoft.VisualBasic . It won't be an either-or situation.

only for RuBoard