Home > Articles > Programming > Visual Studio

  • Print
  • + Share This
This chapter is from the book

Exploring the .NET Framework

The .NET Framework is made up of the common language runtime and a set of code libraries called the Framework Class Library. This framework is a platform for building .NET applications such as Windows applications, Web-based applications, and VSTO customizations. Before delving into the common language runtime, we briefly cover three concepts that are important to programming in managed code: assemblies, namespaces, and application domains.

Assemblies

An assembly is a collection of classes and functionality that is stored as an executable file (.exe) or a library (.dll). When you compile a .NET language such as Visual Basic 2005, your code is not compiled directly into machine language, or binary code. Instead, it is compiled into an assembly-like language known as Intermediate Language (IL). No matter which language you use (Visual Basic 2005 or C#) to create a VSTO solution, the build process compiles the code into IL. The assembly contains both IL and metadata that describes each class and its members, along with information about the assembly itself, such as the assembly name, version, and any dependencies it has.

Assemblies can be private or shared. A private assembly normally contains code that is intended to be used by only one application. These assemblies can reside in the same folder as the application that uses them, or in a subfolder of the application. For example, when you create and build a VSTO solution, the compiled code is saved in a subfolder of your solution.

Shared assemblies, on the other hand, are designed to be shared among many applications. Because any software can access these assemblies, they should be stored in a special directory known as the global assembly cache (GAC). An example of a shared assembly is an Office primary interop assembly (PIA) described later in this chapter.

Namespaces

Namespaces help you organize the objects in an assembly, such as classes, interfaces, structures, enumerations, and other namespaces.

Using namespaces helps you avoid problems such as naming collisions or conflicts within your code. For example, let's say you have a class named Math that contains functionality to add or subtract the value of Excel ranges. You could add a reference to an assembly that contains a class also named Math but having different functionality. When you run your application, there would be no way for the .NET Framework to distinguish between your Math class and the referenced Math class.

Creating namespaces for your classes gives you another level of naming that helps disambiguate your classes. In the same way that using people's last names can help distinguish them from others who share the same first name, using a namespace along with a class name (also known as fully qualifying a class) helps the .NET Framework runtime distinguish one class from a like-named class. Often a company name is used as an alias of a namespace, so, for example, MyCompany.Employees can be easily distinguished from YourCompany.Employees.

To fully qualify the name of an object, you simply prefix the object with the namespace. For example, the Button class that you add to a Word document is in the Microsoft.Office.Tools.Word.Controls namespace and is referenced as Microsoft.Office.Tools.Word.Controls.Button. In contrast, the Button class you add to a Windows Form is in the System.Windows.Forms namespace and is referenced as System.Windows.Forms.Button.

You can include a namespace in your project by using the Imports statement, and you can optionally provide an alias to be used in place of the namespace. For example, you could add the following line to the top of your code file:

Imports Microsoft.Office.Tools.Word

Or, to disambiguate this namespace from the Microsoft.Office.Interop.Word namespace, you might use an alias:

Imports Tools = Microsoft.Office.Tools.Word

In this way, you can refer to an object within that namespace by using the alias. So instead of declaring myBookmark as a Microsoft.Office.Tools.Word.Bookmark, you could declare it as a Tools.Bookmark.

Application Domains

Application domains give the .NET Framework a way to isolate applications that are running in the same process. For example, if you're running multiple add-ins for your application and if one of them needs to be reloaded, you would want to ensure that the other add-ins are not affected. Loading the add-ins into a separate application domain guarantees this isolation. You can run several application domains in a single process and achieve the same level of isolation that exists when you run the applications in separate processes.

You can also set security permissions on an application domain. For example, when an application domain is created for a VSTO solution, the VSTO runtime sets policy for the application domain so that it does not trust the My Computer Zone. This practice ensures that the code in the My Computer Zone has been granted trust explicitly rather than allowing all code to run by default. You'll learn more about security in Chapter 11, Security and Deployment.

Common Language Runtime

The common language runtime is a runtime environment that supports multiple .NET Framework programming languages, such as Visual Basic 2005 and Visual C#. The common language runtime manages your code and provides compilation services, exception handling services, reflection services, memory management services, and a security mechanism for running secure code.

Compilation

At run time, the common language runtime compiles IL code into machine code (binary) that is specific to the hardware and operating system the code is currently running on. The common language runtime compiler is known as the Just-In-Time (JIT) compiler because it doesn't go through and compile all the code in the assembly at one time but rather compiles code only as it is being called. If the same method is called again while the solution is running, the common language runtime runs the binary that is already in memory rather than rerun it through JIT compilation. One benefit of this arrangement is that only the code that needs to be run is compiled, saving time and memory compared with compiling it all at once.

Additionally, the common language runtime can read the metadata of the IL stored in the assembly and can verify that the code is type safe before attempting to access memory locations. Note also that the verification process can be skipped if security policy is set to do so.

Exception Handling

The common language runtime provides an exception notification service so that it's easy to determine that an error has occurred. The .NET Framework provides a number of exception classes that describe the most common types of exceptions. With managed code, you should use structured exception handling—such as Try Catch Finally (Try Catch) statements—to check whether an exception is thrown within your code and handle the exception accordingly. Rather than use the method of error handling used in VBA code (On Error GoTo statements), you should instead favor the more robust exception handling of a Try Catch statement.

A Try Catch statement is made up of a Try block, a Catch block, and an End Try statement. You add the code that can possibly cause an exception in the Try block as a way to "try out" the code. Then you "catch" any exceptions that are thrown by handling the exception in the Catch block.

If needed, you can break out of a Try Catch statement by using the Exit Try keyword. The Finally block is always executed, whether or not an error is raised and handled.

You end a Try Catch statement with End Try. For example, the code in Listing 3.13 shows how you can check whether a folder exists. The code sets a folder named Personnel as the current Outlook folder in a Try block and displays an error in the Catch block if an exception is raised. An exception is raised if inbox.Folders does not contain an entry for "Personnel." Note, however, that it is better to specify the type of exception in the Catch statement (if it is known) than to catch all exceptions as in this example.

Listing 3.13. Try Catch statement

Try
    Me.ActiveExplorer().CurrentFolder = inBox.Folders( _
        "Personnel")
Catch Ex As Exception
    MsgBox(Ex.Message)
End Try

Reflection

Using reflection, you can discover which types exist in an assembly at run time, as well as examine its methods, properties and events, and attributes. Attributes are metadata tags that you can apply to your code. The common language runtime uses classes within the .NET Framework class library that are part of the System.Reflection namespace to programmatically inspect an assembly.

The .NET Framework 2.0 SDK contains a tool named ILDASM that uses reflection to display all the types and members of an assembly. You can also view the assembly's IL. There are other tools that use reflection on an assembly that do not ship with the .NET Framework, such as .NET Reflector.

Garbage Collection

The common language runtime provides automatic memory management known as garbage collection. Garbage collection is a process of releasing memory used to store an object or object reference when it is no longer being used. The garbage collector examines variables and objects and checks whether there are any existing references. If the objects are not being referenced, they are not destroyed; rather, they are flagged for garbage collection. The .NET Framework determines the time frame in which the garbage collection actually occurs.

The garbage collector reclaims any memory that is no longer being used. The garbage collector functionality is exposed through the GC class. At times, you should mark an object as being eligible for garbage collection (for example, setting the object variable to Nothing); at other times, you might want to force a garbage collection to free up memory (for example, calling GC.Collect()). Under normal circumstances you shouldn't force garbage collection.

Security

The common language runtime offers code-based security, in which permissions are based on the identity of the code, rather than role-based security, which is based on the identity, or role, of the user trying to run the code. This security model is known as code access security (CAS), and the security policy set determines what the code can do and how much the code is trusted. Security is covered in more detail in Chapter 11.

Common Language Specification

For code to interact with objects implemented in any language, the objects must expose common features to the common language runtime. The Common Language Specification (CLS) defines the rules that must be adhered to. For example, it specifies that arrays must have a lower bound of zero.

The common type system, which defines how types are declared and used, is defined in the CLS. The common type system ensures that objects written in different languages can interact. All types derive from System.Object, and they are typically classified into value types and reference types.

Value Types and Reference Types

There are two main categories of types that are managed by the common language runtime: value types and reference types. The difference between them is that reference types, such as objects, are stored on a portion of memory in the computer called the heap, whereas value types, such as numeric data types, are stored on another portion of memory called the stack.

Value types include structures, the numeric data types (Byte, Short, Integer, Long, Single, Double), enumerations, Boolean, Char, and Date. Reference types include classes, delegates, arrays, and Strings, and they can be accessed only through a reference to their location. When you create a variable for a value type without assigning it a value, the type is automatically initialized to a default value.

Table 3.1 lists some common data types, shows how they map to the System namespace in the .NET class library, and lists their default values. When you create a reference type variable, however, its value defaults to Nothing.

Table 3.1. Default Value for Data Types

Data Type

Namespace Map

Default Value

Byte

System.Byte

0

Short

System.Int16

0

Integer

System.Int32

0

Long

System.Int64

0

Single

System.Single

0

Double

System.Double

0

Decimal

System.Decimal

0D

Boolean

System.Boolean

False

Date

System.DateTime

01/01/0001 12:00:00AM

String

System.String

Nothing

.NET Framework Class Library

As the name suggests, the .NET Framework class library is a library of classes that contains popular functionality for use in your code. For example, an XMLReader class in the System.XML namespace gives you quick access to XML data. Instead of writing your own classes or functionality, you can use any of the thousands of classes and interfaces—such as Windows Forms controls and input/output (IO) functions—that are included in the .NET Framework class library. You can also derive your own classes from classes in the .NET Framework. When you're working with the Framework class library, it's important to understand that these classes are organized within the context of namespaces.

The .NET Framework class library is organized into hierarchical namespaces according to their functionality. This arrangement makes it easier to locate functionality within the library and provides a way to disambiguate class names. A number of namespaces are automatically imported, or referenced, when you create a project in Visual Studio. For example, in a Windows Forms application, you do not need to fully qualify the Button class as Microsoft.Windows.Forms.Button, because the Microsoft.Windows.Forms namespace is automatically imported into your project. Instead, you can refer to the Button class directly. When you're using Visual Studio Tools for Office, however, there is a Button class in Excel and Word that differs from the Windows Forms Button class. In this case, you must fully qualify any references to the VSTO Button. The code example in Listing 3.14 illustrates.

Listing 3.14. Fully qualifying an object

' Declare a variable for a Windows Forms button.
Dim myButton As Button

' Declare a variable for a button to be used on a Word document.
Dim myWordButton As Microsoft.Office.Tools.Word.Button

In Visual Basic, you can use an Imports statement at the top of your code file to include a namespace in your project. In this way, you do not have to type the fully qualified namespace every time you reference the classes within that namespace. You can also create an alias for the namespace, as shown in Listing 3.15.

Listing 3.15. Creating an alias for a namespace

Imports Tools = Microsoft.Office.Tools.Word

Sub Test()
    ' Declare a variable for a Windows Forms button.
    Dim myButton As Button

    ' Declare a variable for a button to be used on a
    ' Word document.
    Dim MyWordButton As Tools.Button
End Sub

Table 3.2 lists some of the popular namespaces in the .NET Framework class library that you might use in your VSTO solutions.

Table 3.2. Popular Namespaces in the .NET Framework Class Library

Namespace

Description

System

Contains the base data types, such as String, Boolean, and Object. This namespace is automatically included in your project, so you need not qualify any of the types in this namespace. Most languages, including Visual Basic 2005, define their own data types, which typically map to the types in this namespace. This is one reason for some of the language changes (data type changes) between VBA and Visual Basic 2005. For example, a Short in Visual Basic 2005 is equivalent to an Integer in VBA, and the Variant data type in VBA is no longer supported. These types were updated in Visual Basic 2005 to conform to the types in the System namespace.

In addition to providing the base data types, the System namespace has classes such as exception classes and the Math class (for computations).

System.Collections

Contains classes and interfaces used to define collections of objects, such as the ArrayList, CollectionBase, and SortedList classes. This namespace is typically used to create collection classes and also contains many generic collection classes.

System.Data

Contains the classes for ADO.NET. You need references to this namespace when creating data binding in VSTO objects. Defined types in this namespace include the IDbConnection interface, IDataAdapter interface, and DataSet class.

System.IO

Contains the classes for reading and writing files synchronously or asynchronously. Objects defined in this namespace include the File, Directory, and Stream classes.

System.Text

Contains the StringBuilder class and supports various String manipulation functions, such as insert or remove text and others. You do not need to create a new String object, which the concatenation operator (&) implicitly does, in order to modify a string.

System.Windows.Forms

Contains a number of control classes that can be added to a form to create rich GUI applications. The controls include DateTimePicker, Textbox, Button, and ListBox.

System.Xml

Used for processing XML. This namespace includes a reader for parsing XML and classes such as XmlDocument and XmlNode.

To use a .NET Framework class in your code, you must first set a reference to the assembly that contains the class. To set a reference, you click Add Reference from the Project menu. When the Add Reference dialog box appears, you select the component name from the .NET tab and then click OK to add the reference and close the dialog box. Figure 3.6 shows the Add Reference dialog box in Visual Studio. You can also set references to component object model (COM) type libraries or browse to a particular assembly on your system. All references to your project are displayed in the References node in Solution Explorer. You might have to click Show All Files to view the references.

Figure 3.6

Figure 3.6 The Add Reference dialog box in Visual Studio

After setting the reference, you can add an Imports statement at the top of your code file so that you don't have to fully qualify an object in the namespace. You can optionally create an alias for the namespace as was shown in Listing 3.15. Some namespaces, such as the System namespace, are automatically included in your solution; therefore, it is not necessary to add a reference or create an alias for these namespaces.

  • + Share This
  • 🔖 Save To Your Account