MCAD/MCSD Self-Paced Training Kit: Developing Windows-Based Applications with Microsoft Visual Basic.Net and Microsoft Visual C#.NET
  • Alternative view 1 of MCAD/MCSD Self-Paced Training Kit: Developing Windows-Based Applications with Microsoft Visual Basic.Net and Microsoft Visual C#.NET
  • Alternative view 2 of MCAD/MCSD Self-Paced Training Kit: Developing Windows-Based Applications with Microsoft Visual Basic.Net and Microsoft Visual C#.NET

MCAD/MCSD Self-Paced Training Kit: Developing Windows-Based Applications with Microsoft Visual Basic.Net and Microsoft Visual C#.NET

by Matthew A. Stoecker, Matthew Stoecker, Microsoft Corporation

Build real-world programming skills—and prepare for MCP Exams 70-306 and 70-316—with this official Microsoft study guide. Work at your own pace through the lessons and hands-on exercises to learn how to build Windows-based applications using Visual Basic .NET and Visual C# .NET. Then extend your expertise through additional skill-building exercises. As


Build real-world programming skills—and prepare for MCP Exams 70-306 and 70-316—with this official Microsoft study guide. Work at your own pace through the lessons and hands-on exercises to learn how to build Windows-based applications using Visual Basic .NET and Visual C# .NET. Then extend your expertise through additional skill-building exercises. As you gain practical experience with essential development tasks, you’re also preparing for MCAD or MCSD certification for Microsoft .NET.

Learn how to:

  • Create the user interface, add controls, and validate user input
  • Use OOP techniques, including encapsulation and method overloading
  • Build custom controls and .NET assemblies
  • Access and modify data using XML, Microsoft ADO.NET, and SQL syntax
  • Implement print support, online help, and accessibility and globalization features
  • Test and debug coding errors
  • Configure and help secure an application
  • Deploy applications via removable media, the Web, or a network
  • Maintain and optimize application performance

Your kit includes:

  • NEW—60-day evaluation version of Microsoft Visual Studio® .NET 2003 Professional Edition on DVD
  • Comprehensive self-paced study guide that maps to the objectives of the final exams
  • NEW—Expanded coverage of ADO.NET, SQL syntax, Windows Forms, debugging, and security
  • NEW—150 challenging practice questions on CD. Test yourself by exam (70-306 or 70-316) or by individual objective(s). Choose the number of questions and timed or untimed mode. You get automated scoring and detailed explanations for both correct and incorrect answers.
  • Learn-by-doing exercises for skills you can apply to the job
  • Side-by-side code examples and labs for Visual C# .NET and Visual Basic .NET
  • Fully searchable eBook

A Note Regarding the CD or DVD

The print version of this book ships with a CD or DVD. For those customers purchasing one of the digital formats in which this book is available, we are pleased to offer the CD/DVD content as a free download via O'Reilly Media's Digital Distribution services. To download this content, please visit O'Reilly's web site, search for the title of this book to find its catalog page, and click on the link below the cover image (Examples, Companion Content, or Practice Files). Note that while we provide as much of the media content as we are able via free download, we are sometimes limited by licensing restrictions. Please direct any questions or concerns to

Product Details

Microsoft Press
Publication date:
Edition description:
2nd ed.
Product dimensions:
7.50(w) x 9.30(h) x 1.77(d)

Read an Excerpt

  • Lesson 1: The .NET Framework and the Common Language Runtime
  • Lesson 2: The .NET Base Class Library
  • Lesson 3: Using Classes and Structures
  • Lesson 4: Using Methods
  • Lesson 5: Scope and Access Levels
  • Lesson 6: Garbage Collection
  • Lab 1: Classes and Garbage Collection
  • Review

Chapter 1  Introduction to the .NET Framework

About This Chapter

This chapter discusses the Microsoft .NET Framework and the common language runtime. It also provides an introduction to the syntax of class, structure, and method declaration.

Before You Begin

There are no prerequisites to completing the lessons in this chapter.

Lesson 1: The .NET Framework and the Common Language Runtime

The Microsoft .NET Framework is an integrated and managed environment for the development and execution of your code. This lesson is an introduction to the .NET Framework, the philosophy behind it, and how it works.

After this lesson, you will be able to

  • Describe the elements of the .NET Framework
  • Describe the parts of an assembly and identify what is contained in each part
  • Describe how a .NET application is compiled and executed

Estimated lesson time: 20 minutes

Overview of the .NET Framework

The .NET Framework is a managed type-safe environment for application development and execution. The .NET Framework manages all aspects of your program’s execution. It allocates memory for the storage of data and instructions, grants or denies the appropriate permissions to your application, initiates and manages application execution, and manages the reallocation of memory from resources that are no longer needed. The .NET Framework consists of two main components: the common language runtime and the .NET Framework class library.

The common language runtime can be thought of as the environment that manages code execution. It provides core services, such as code compilation, memory allocation, thread management, and garbage collection. Through the common type system (CTS), it enforces strict type-safety and ensures that code is executed in a safe environment by also enforcing code access security.

The .NET Framework class library provides a collection of useful and reusable types that are designed to integrate with the common language runtime. The types provided by the .NET Framework are object-oriented and fully extensible, and they allow you to seamlessly integrate your applications with the .NET Framework. The .NET base class library is discussed further in Lesson 2 of this chapter.

Languages and the .NET Framework

The .NET Framework is designed for cross-language compatibility, which means, simply, that .NET components can interact with each other no matter what supported language they were written in originally. So, an application written in Microsoft Visual Basic .NET might reference a dynamic-link library (DLL) file written in Microsoft Visual C#, which in turn might access a resource written in managed Microsoft Visual C++ or any other .NET language. This language interoperability extends to full object-oriented inheritance. A Visual Basic .NET class might be derived from a C# class, for example, or vice versa.

This level of cross-language compatibility is possible because of the common language runtime. When a .NET application is compiled, it is converted from the language in which it was written (Visual Basic .NET, C#, or any other .NET-compliant language) to Microsoft Intermediate Language (MSIL or IL). MSIL is a low-level language that the common language runtime can read and understand. Because all .NET executables and DLLs exist as MSIL, they can freely interoperate. The Common Language Specification (CLS) defines the minimum standards to which .NET language compilers must conform. Thus, the CLS ensures that any source code successfully compiled by a .NET compiler can interoperate with the .NET Framework.

The CTS ensures type compatibility between .NET components. Because .NET applications are converted to IL prior to deployment and execution, all primitive data types are represented as .NET types. Thus, a Visual Basic Integer and a C# int are both represented in IL code as a System.Int32. Because both languages use a common type system, it is possible to transfer data between components and avoid time-consuming conversions or hard-to-find errors.

Visual Studio .NET ships with languages such as Visual Basic .NET, Visual C#, and Visual C++ with managed extensions, as well as the JScript scripting language. You can also write managed code for the .NET Framework in other languages. Third-party tools and compilers exist for Fortran, Cobol, Perl, and a host of other languages. All of these languages share the same cross-language compatibility and inheritability. Thus, you can write code for the .NET Framework in the language of your choice, and it will be able to interact with code written for the .NET Framework in any other language.

The Structure of a .NET Application

To understand how the common language runtime manages code execution, you must examine the structure of a .NET application. The primary unit of a .NET application is the assembly. An assembly is a self-describing collection of code, resources, and metadata. The assembly manifest contains information about what is contained within the assembly. The assembly manifest provides:

  • Identity information, such as the assembly’s name and version number
  • A list of all types exposed by the assembly
  • A list of other assemblies required by the assembly
  • A list of code access security instructions, including permissions required by the assembly and permissions to be denied the assembly

Each assembly has one and only one assembly manifest, and it contains all the description information for the assembly. However, the assembly manifest can be contained in its own file or within one of the assembly’s modules.

An assembly contains one or more modules. A module contains the code that makes up your application or library, and it contains metadata that describes that code. When you compile a project into an assembly, your code is converted from high-level code to IL. Because all managed code is first converted to IL code, applications written in different languages can easily interact. For example, one developer might write an application in Visual C# that accesses a DLL in Visual Basic .NET. Both resources will be converted to IL modules before being executed, thus avoiding any language-incompatibility issues.

Each module also contains a number of types. Types are templates that describe a set of data encapsulation and functionality. There are two kinds of types: reference types (classes) and value types (structures). These types are discussed in greater detail in Lesson 2 of this chapter. Each type is described to the common language runtime in the assembly manifest. A type can contain fields, properties, and methods, each of which should be related to a common functionality. For example, you might have a class that represents a bank account. It contains fields, properties, and methods related to the functions needed to implement a bank account. A field represents storage of a particular type of data. One field might store the name of an account holder, for example. Properties are similar to fields, but properties usually provide some kind of validation when data is set or retrieved. You might have a property that represents an account balance. When an attempt is made to change the value, the property can check to see if the attempted change is greater than a predetermined limit. If the value is greater than the limit, the property does not allow the change. Methods represent behavior, such as actions taken on data stored within the class or changes to the user interface. Continuing with the bank account example, you might have a Transfer method that transfers a balance from a checking account to a savings account, or an Alert method that warns users when their balances fall below a predetermined level.

Compilation and Execution of a .NET Application

When you compile a .NET application, it is not compiled to binary machine code; rather, it is converted to IL. This is the form that your deployed application takes—one or more assemblies consisting of executable files and DLL files in IL form. At least one of these assemblies will contain an executable file that has been designated as the entry point for the application.

When execution of your program begins, the first assembly is loaded into memory. At this point, the common language runtime examines the assembly manifest and determines the requirements to run the program. It examines security permissions requested by the assembly and compares them with the system’s security policy. If the system’s security policy does not allow the requested permissions, the application will not run. If the application passes the system’s security policy, the common language runtime executes the code. It creates a process for the application to run in and begins application execution. When execution starts, the first bit of code that needs to be executed is loaded into memory and compiled into native binary code from IL by the common language runtime’s Just-In-Time (JIT) compiler. Once compiled, the code is executed and stored in memory as native code. Thus, each portion of code is compiled only once when an application executes. Whenever program execution branches to code that has not yet run, the JIT compiler compiles it ahead of execution and stores it in memory as binary code. This way, application performance is maximized because only the parts of a program that are executed are compiled.

Lesson Summary

  • The .NET Framework is a foundation for software development. The .NET Framework consists of the common language runtime, which provides many of the core services required for program execution, and the .NET base class library, which exposes a set of pre-developed classes to facilitate program development. The CLS defines a minimum set of standards that all languages using the .NET Framework must support, and the CTS ensures type compatibility between components developed in different languages.
  • The primary unit of a .NET application is the assembly, which includes an assembly manifest. The assembly manifest describes the assembly and one or more modules, and the modules contain the source code for the application.
  • A .NET executable is stored as an IL file. When loaded, the assembly is checked against the security policy of the local system. If it is allowed to run, the first assembly is loaded into memory and JIT compiled into native binary code, where it is stored for the remainder of the program’s execution.

Lesson 2: The .NET Base Class Library

The .NET base class library is a collection of object-oriented types and interfaces that provide object models and services for many of the complex programming tasks you will face. Most of the types presented by the .NET base class library are fully extensible, allowing you to build types that incorporate your own functionality into your managed code. This lesson introduces some of the .NET base class library namespaces and describes how to reference the library and use its types and methods.

After this lesson, you will be able to

  • Describe the .NET base class library
  • Explain the difference between value types and reference types
  • Create a reference to a namespace
  • Create an instance of a .NET Framework class and value type

Estimated lesson time: 30 minutes

The .NET Framework base class library contains the base classes that provide many of the services and objects you need when writing your applications. The class library is organized into namespaces. A namespace is a logical grouping of types that perform related functions. For example, the System.Windows.Forms namespace contains all the types that make up Windows forms and the controls used in those forms.

Namespaces are logical groupings of related classes. The namespaces in the .NET base class library are organized hierarchically. The root of the .NET Framework is the System namespace. Other namespaces can be accessed with the period operator. A typical namespace construction appears as follows:


The first example refers to the System namespace. The second refers to the System.Data namespace. The third example refers to the System.Data.SQLClient namespace. Table 1.1 introduces some of the more commonly used .NET base class namespaces.

Table 1.1  Representative .NET Namespaces

SystemThis namespace is the root for many of the low-level types required by the .NET Framework. It is the root for primitive data types as well, and it is the root for all the other namespaces in the .NET base class library.
System.CollectionsThis namespace contains classes that represent a variety of different container types, such as ArrayList, SortedList, Queue, and Stack. You also can find abstract classes, such as CollectionBase, which are useful for implementing your own collection functionality.
System.ComponentModelThis namespace contains classes involved in component creation and containment, such as attributes, type converters, and license providers.
System.DataThis namespace contains classes required for database access and manipulations, as well as additional namespaces used for data access.
System.Data.CommonThis namespace contains a set of classes that are shared by the .NET managed data providers.
System.Data.OleDbThis namespace contains classes that make up the managed data provider for OLE DB data access.
System.Data.SQLClientThis namespace contains classes that are optimized for interacting with Microsoft SQL Server.
System.DrawingThis namespace exposes GDI+ functionality and provides classes that facilitate graphics rendering.
System.IOIn this namespace, you will find types for handling file system I/O.
System.MathThis namespace is home to common mathematics functions such as extracting roots and trigonometry.
System.ReflectionThis namespace provides support for obtaining information and dynamic creation of types at runtime.
System.SecurityThis namespace is home to types dealing with permissions, cryptography, and code access security.
System.ThreadingThis namespace contains classes that facilitate the implementation of multithreaded applications.
System.Windows.FormsThis namespace contains types involved in creating standard Windows applications. Classes that represent forms and controls reside here as well.

The namespace names are self-descriptive by design. Straightforward names make the .NET Framework easy to use and allow you to rapidly familiarize yourself with its contents.

Reference Types and Value Types

Types in the .NET Framework come in two varieties: value types and reference types. The primary difference between value types and reference types has to do with the way variable data is accessed. To understand this difference, a little background on memory dynamics is required.

Application data memory is divided into two primary components, the stack and the heap. The stack is an area of memory reserved by the application to run the program. The stack is analogous to a stack of dinner plates. Plates are placed on the stack one on top of another. When a plate is removed from the stack, it is always the last one to have been placed on top that is removed first. So it is with program variables. When a function is called, all the variables used by the function are pushed onto the stack. If that function calls additional functions, it pushes additional variables onto the stack. When the most recently called function terminates, all of its variables go out of scope (meaning that they are no longer available to the application) and are popped off the stack. Memory consumed by those variables is then freed up, and program execution continues.

The heap, on the other hand, is a separate area of memory reserved for the creation of reusable objects. The common language runtime manages allocation of heap memory for objects and controls the reclamation of memory from unused objects through garbage collection.

Garbage collection is discussed further in Lesson 6 of this chapter.

All the data associated with a value type is allocated on the stack. When a variable of a value type goes out of scope, it is destroyed and its memory is reclaimed. A variable of a reference type, on the other hand, exists in two memory locations. The actual object data is allocated on the heap. A variable containing a pointer to that object is allocated on the stack. When that variable is called by a function, it returns the memory address for the object to which it refers. When that variable goes out of scope, the object reference is destroyed but the object itself is not. If any other references to that object exist, the object remains intact. If the object is left without any references, it is subject to garbage collection. (See Lesson 6 of this chapter.)

Examples of value types include primitives, such as Integer (int), Boolean (bool), Char (char), and so on, as well as user-defined types such as Structure (struct) and Enumeration (enum). Classes represent the majority of reference types. Other reference types include the interface, delegate, and array types. Classes and structures are discussed in Lesson 3 of this chapter, and other reference and value types are discussed in Chapter 3.

Throughout this book, when Visual Basic and Visual C# terms are mentioned together, the Visual Basic term appears first, followed by the C# term in parentheses.

Using .NET Framework Types in Your Application

When you begin writing an application, you automatically begin with a reference to the .NET Framework base class library. You reference it so that your application is aware of the base class library and is able to create instances of the types represented by it.

Value Types

In Visual Basic .NET, you use the Dim statement to create a variable that represents a value type. In C#, you create a variable by declaring its type and then the variable name. The following code is an example:

Visual Basic .NET

Dim myInteger As Integer

Visual C#

int myInteger;

This line tells the runtime to allocate the appropriate amount of memory to hold an integer variable. Although this line creates the variable, it does not assign a value to it. You can assign a value using the assignment operator, as follows:

Visual Basic .NET

myInteger = 42

Visual C#

myInteger = 42;

You can also choose to assign a value to a variable upon creation, as shown in this example:

Visual Basic .NET

Dim myInteger As Integer = 42

Visual C#

int myInteger = 42;

Although declaration and initialization on a single line was discouraged in Visual Basic 6, there is no performance drawback to single-line declaration and initialization in Visual Basic .NET.

Reference Types

Creating an instance of a type is a two-step process. The first step is to declare the variable as that type, which allocates the appropriate amount of memory for that variable but does not actually create the object. The following syntax declares an object:

Visual Basic .NET

Dim myForm As System.Windows.Forms.Form

Visual C#

System.Windows.Forms.Form myForm;

This line tells the runtime to set aside enough memory to hold a Form variable and assigns it the name myForm, but it does not actually create the Form object in memory. The second step, called instantiation, actually creates the object. An example of instantiation follows:

Visual Basic .NET

myForm = New System.Windows.Forms.Form()

Visual C#

myForm = new System.Windows.Forms.Form();

This line makes a call to the constructor method of the type System.Windows.Forms.Form by way of the New (new) keyword. The constructor is a special method that is invoked only at the beginning of an object’s lifetime. It contains any code that must be executed for the object to work (assigning values to properties, for example). If any parameters were required by the constructor, they would be contained within the parentheses at the end of the line. The following example shows declaration and instantiation of a hypothetical Widget class that requires a string as a parameter in the constructor. For further discussion of the constructor, see Lesson 4 in this chapter.

Visual Basic .NET

Dim myWidget As Widget
myWidget = New Widget("This string is required by the constructor")

Visual C#

Widget myWidget;
myWidget = new Widget("This string is required by the constructor");

If desired, you can also combine both declaration and instantiation into a single statement. By declaring and instantiating an object in the same line, you reserve the memory for the object and immediately create the object that resides in that memory. Although there was a significant performance penalty for this shortcut in previous versions of Visual Basic, Visual Basic .NET and Visual C# are optimized to allow this behavior without any performance loss. The following example shows the one-step declaration and instantiation of a new Form:

Visual Basic .NET

Dim myForm As New System.Windows.Forms.Form()

Visual C#

System.Windows.Forms.Form myForm = new 

Both value types and reference types must be initialized before use. For class and structure fields in Visual Basic .NET, types are initialized with default values on declaration. Numeric value types (such as integer) and floating-point types are assigned zero; Boolean variables are assigned False; and reference types are assigned to a null reference.

In C#, variables of a reference type have a default value of null. It is recommended that you do not rely on the default value. These variables should not be used until they have been initialized.

Using Value Type and Reference Type Variables

A variable that represents a value type contains all the data represented by that type. A variable that represents a reference type contains a reference to a particular object. This distinction is important. Consider the following example:

Visual Basic .NET

Dim x, y As integer 
x = 15
y = x
x = 30
‘ What is the value of y?

Visual C#

int x, y;
x = 15;
y = x;
x = 30;
// What is the value of y? 

In this example, two integer variables named x and y are created. X is assigned a value of 15, and then y is assigned the value of x. Next the value of x is changed to 30, and the question is posed: what is the value of y? The answer to this question might seem obvious, and it is y = 15 because x and y are two separate variables and have no effect on each other when changed. When the line y = x is encountered, the value of x is copied to the value of y, and there is no further connection between the two variables.

This situation changes, however, in the case of reference types. Let’s reconsider the previous example using a reference type (Form) instead of a value type.

Visual Basic .NET

Dim x, y As System.Windows.Forms.Form 
x = New System.Windows.Forms.Form()
x.Text = "This is Form 1"
y = x
x.Text = "This is Form 2"
‘ What value does y.Text return?

Visual C#

System.Windows.Forms.Form x,y;
x = new System.Windows.Forms.Form();
x.Text = "This is Form 1";
y = x;
x.Text = "This is Form 2";
// What value does y.Text return? 

What value does y.Text return? This time, the answer is less obvious. Because System.Windows.Forms.Form is a reference type, the variable x does not actually contain a Form; rather, it points to an instance of a Form. When the line y = x is encountered, the runtime copies the reference from variable x to y. Thus, the variables x and y now point to the same instance of Form. Because these two variables refer to the same instance of the object, they will return the same values for properties of that object. Thus, y.Text returns "This is Form 2".

The Imports and Using Statements

Up to this point of the chapter, if you wanted to access a type in the .NET Framework base class library, you had to use the full name of the type, including every namespace to which it belonged. For example:


This is called the fully-qualified name, meaning it refers both to the class and to the namespace in which it can be found. You can make your development environment "aware" of various namespaces by using the Imports (Visual Basic .NET) or using (Visual C#) statement. This technique allows you to refer to a type using only its generic name and to omit the qualifying namespaces. Thus, you could refer to System.Windows.Forms.Form as simply Form. In Visual Basic .NET, the Imports statement must be placed at the top of the code window, preceding any other statement (except Option). In Visual C#, the using statement must occur before any other namespace element, such as a class or struct. This example demonstrates use of this statement:

Visual Basic .NET

Imports System.Windows.Forms

Visual C#

using System.Windows.Forms;

When two types of the same name exist in more than one imported namespace, you must use the fully qualified name to avoid a naming conflict. Thus, if you are using MyNameSpaceOne and MyNameSpaceTwo, and each contains a Widget class, you would have to refer to MyNameSpaceOne.Widget or MyNameSpaceTwo.Widget to ensure the correct result.

In C#, you can resolve namespace conflicts such as these by creating an alias. An alias allows you to choose one name to refer to another class. You create an alias using the using keyword, as shown below:

Visual C#

using myAlias = MyNameSpaceTwo.Widget;

After implementing an alias, you can use it in code to represent the aliased class. For example:

Visual C#

// You can now refer to MyNameSpaceTwo as myAlias. The 
// following two lines produce the same result:
MyNameSpaceTwo.Widget anotherWidget = new MyNameSpaceTwo.Widget() ;
myAlias anotherWidget = new myAlias() ;

You cannot create aliases for types in this manner in Visual Basic .NET.

Referencing External Libraries

You might want to use class libraries not contained by the .NET Framework, such as libraries developed by third-party vendors or libraries you developed. To access these external libraries, you must create a reference.

To create a reference to an external library

  1. In the Solution Explorer, right-click the References node of your project.
  2. From the pop-up menu, choose Add Reference. The Add Reference dialog box appears.
  3. Choose the appropriate tab for the library you want to reference. .NET libraries are available on the .NET tab. Legacy COM libraries appear on the COM tab, and local Visual Studio projects appear on the Projects tab.
  4. Locate the library you want to reference, and double-click it to add it to the Selected components box. Click OK to confirm the choice of that reference.

Lesson Summary

  • The .NET Framework base class library is a library of code that exposes functionality useful for application building. The base class library is organized into namespaces, which contain types and additional namespaces related to common functionality.
  • Types can be either value types or reference types. A variable of a value type contains all the data associated with that type. A variable of a reference type contains a pointer to an instance of an object of that type.
  • Non-user-defined value types are created on declaration and remain empty until they are assigned a value. Reference types must be instantiated after declaration to create the object. Declaration and instantiation can be combined into a single step without any loss of performance.
  • When a value type variable is assigned to another value type variable, the data contained within the first variable is copied into the second. When a reference type variable is assigned to another reference type variable, only the reference to the object is copied, and both variables will refer to the same object.
  • You can use the using or Imports statements to allow references to members of a namespace without using the fully qualified name. If you want to use an external library, you must create a reference to it.

Lesson 3: Using Classes and Structures

You have seen how the .NET Framework base class library provides a plethora of standard types to help you in the development of your applications. You can also create user-defined types that implement custom behaviors. Classes and structures represent the two principal user-defined types.

After this lesson, you will be able to

  • Create a new class or structure
  • Create an instance of a class or a structure
  • Explain the difference between a class and a structure
  • Create a nested type

Estimated lesson time: 30 minutes

Classes are templates for objects. They describe the kind and amount of data that an object will contain, but they do not represent any particular instance of an object. A real-world example of a class might be "Car"—the abstract idea of what a car is. You know that a car has an engine, four wheels, a body color, an individual fuel efficiency, and a dozen other properties. Although the Car class would describe all these properties, as well as have descriptions of actions that the car might perform (roll forward, turn on windshield wipers, and so on), the class would not represent any particular car. Your car, on the other hand, is an object. It has a specific color, a specific fuel efficiency, a specific engine, and four specific wheels. A different car might have different values for each of these properties, but both would be recognizable as being an instance of the Car class.


Classes describe the properties and behaviors of the objects they represent through members. Members are methods, fields, properties, and events that belong to a particular class. Fields and properties represent the data about an object—the color of the car, its fuel efficiency, and whether it has an automatic or manual transmission, for example. A method represents something the object can do, such as move forward or turn on headlights. An event represents something interesting that happens to the object, such as overheating or crashing.

This chapter discusses fields and methods. Properties and events are covered in Chapter 3.

Creating Classes

You create a new class by using the Class (Visual Basic .NET) or class (C#) keyword. For example:

Visual Basic .NET

Public Class Widget
‘ Class member implementation goes here
End Class

Visual C#

public class Widget

   // Class member implementation goes here

In this example, you use the Class (class) keyword to create a user-defined class. Widget is the name of the class, and the Public (public) keyword specifies the access level. Access levels are examined in greater detail in Lesson 5 of this chapter.

Creating Structures

Creating structures is very similar to creating classes. You use the Structure (Visual Basic .NET) or struct (C#) keyword. For example:

Visual Basic .NET

Public Structure Vector
   ’ Structure implementation goes here
End Structure

Visual C#

public struct Vector
   // Structure implementation goes here

Adding Members

In Visual Basic .NET, a class comprises everything between the Class keyword and the End Class keyword. In C#, a class comprises everything within braces ({}). Structures are similar. Within the bounds of a class or a structure, you add the members. The following example demonstrates adding a member field to your Widget class:

Visual Basic .NET

Public Class Widget
   Public Spin As Integer
End Class

Visual C#

public class Widget
   public int Spin;

Your Widget class now contains a member variable named Spin. This variable has a Public (public) access level and can contain an Integer (int) value. Adding methods as members of your class or structure is discussed in Lesson 4 of this chapter.

Nested Types

Types can contain other types. Types within types are called nested types. Using classes as an example, a nested class usually represents an object that the parent class might need to create and manipulate, but which an external object would never need to create independently. An abstract example might be a Wheel class. A Wheel class might need to create and maintain a collection of Spoke objects internally, but outside users would probably never need to create a Spoke object independent of a wheel. A more realistic example might be an AccountManager class that controls all the interaction with Account objects. You might not want to allow Account objects to be created independently of the AccountManager class, so you would make Account a nested class inside AccountManager. This does not mean that outside objects can never instantiate objects based on nested classes—this depends on the access level of both the parent class and the nested class. See Lesson 5 of this chapter for more detail. An example of a nested class follows:

Visual Basic .NET

Public Class Widget
   ’ Widget Class code goes here
   Private Class Widgurt
   ’ Widgurt class code goes here
   End Class
End Class

Visual C#

public class Widget
   // Widget class code goes here
   private class Widgurt
      // Widgurt class code goes here.

Instantiating User-Defined Types

You declare and instantiate a user-defined type the same way that you declare and instantiate a .NET Framework type. For both value types (structures) and reference types (classes), you need to declare the variable as a variable of that type and then create an instance of it with the New (new) keyword. Examples are as follows:

Visual Basic .NET

Public Class Demo
   Public Structure ValueDemo
      Public X As Integer      
   End Structure
   Public Class RefDemo
      Public Y As Integer
   End Class
   Public Sub InstantiateTypes()
      ’ This line declares a ValueDemo variable
      Dim DemoStructure As ValueDemo
      ’ This line creates an instance of ValueDemo on the stack
      DemoStructure = New ValueDemo()
      ’ The variable is ready to receive data.
      DemoStructure.X = 15
      ’ This line declares a RefDemo variable, but doesn’t 
      ’ create an instance of the class
      Dim DemoClass As RefDemo
      ’ This line actually creates the object
      DemoClass = New RefDemo()
      ’ And you can now assign value to its members
       DemoClass.Y = 15
   End Sub
End Class

Visual C#

public class Demo
   public struct ValueDemo
      public int X;
   public class RefDemo
      public int Y;
   public void InstantiateTypes()
      // This line declares a ValueDemo variable
      ValueDemo DemoStructure;
      // This line creates an instance of ValueDemo on the stack
       DemoStructure = new ValueDemo();
      // The variable is ready to receive data
      DemoStructure.X = 15;
      // This line declares a RefDemo variable, but doesn’t create
      // an instance of the class
      RefDemo DemoClass;
      DemoClass = new RefDemo();
      // And you can now assign value to its members
      DemoClass.Y = 15;

Classes vs. Structures

On the surface, classes and structures appear to be very similar. Both can contain members such as fields and methods, both require a constructor to create a new instance of themselves, and like all types in the .NET Framework, both inherit from Object. The key difference between classes and structures is that classes are reference types and structures are value types. On a low level, this means that the instance data for classes is allocated on the heap, whereas the instance data for structures is allocated on the stack. Access to the stack is designed to be light and fast, but storage of large amounts of data on the stack can impede overall application performance.

In practical terms, that structures are best used for smaller, lightweight objects that contain relatively little instance data or for objects that do not persist for long. Classes are best used for larger objects that contain more instance data and are expected to exist in memory for extended periods.

Lesson Summary

  • User-defined types include classes and structures. Both can have members, which are fields, properties, methods, or events. Classes are reference types, and structures are value types.
  • The Class keyword is used to create new classes in Visual Basic .NET and the class keyword is used for Visual C#. Structures are created by using the Structure keyword in Visual Basic .NET and the struct keyword in Visual C#. Both classes and structures can contain nested types.
  • User-defined types are instantiated in the same manner as predefined types, except that both value types and reference types must use the New (new) keyword upon instantiation.

Lesson 4: Using Methods

Methods do the work of classes and structures. They calculate values, update data, receive input, and perform all the manipulations that make up the behavior of a type. In this lesson, you will learn how to create methods, use parameters, and create constructors and destructors for your class.

After this lesson, you will be able to

  • Create a new method
  • Specify return types for your method
  • Specify input and output parameters for your method
  • Create a constructor and a destructor for your class

Estimated lesson time: 45 minutes

Adding Methods

You can add methods as members to your classes. Methods represent actions your class can take. Methods generally come in two varieties: those that return a value (functions in Visual Basic) and those that do not return a value (subs in Visual Basic). The following code shows an example of both kinds of methods:

Visual Basic .NET

Public Sub MySub()
   MessageBox.Show("This is a non-value returning method")
End Sub
‘ Note that the underscore symbol ( _ ) is used in 
‘ Visual Basic .NET to continue a line from one line to the next.
Public Function Add(ByVal first as Integer, ByVal second as _ 
   Integer) As Integer
   Dim Result as Integer
   Result = first + second
   Return Result
End Function

Visual C# makes no distinction between methods that return a value and methods that do not. In either case, you must specify the return value type. If the method does not return a value, its return type is void. Here are examples of C# methods:

Visual C#

public void myVoidMethod()
   MessageBox.Show("This method doesn’t return a value");
 public int Add(int first, int second)
   int Result;
   Result = first + second;
   return Result;

Calling Methods

A method does not execute until it is called. You can call a method by referencing its name along with any required parameters. For example:

Visual Basic .NET

‘ This line calls the Rotate method, with two parameters
Rotate(45, "Degrees")

Visual C#

// This line calls the Rotate method, with two parameters
Rotate(45, "Degrees");

The Main method is a special case. It is called upon initiation of program execution. Destructors, another special case, are called by the runtime just prior to destruction of an object. Constructors, a third special case, are executed by an object during its initialization. These methods are discussed further later in this lesson.

Method Variables

Variables declared within methods are said to have method scope, which means that once the methods complete execution, they are destroyed and their memory reclaimed. They are said to have gone out of scope.

Variables within smaller divisions of methods have even more limited scope. For example, variables declared within a For-Next (for) loop are accessible only within the loop. The following example demonstrates this because the variable Y has gone out of scope:

Visual Basic .NET

Public Sub myMethod()
   Dim X as Integer
   For X = 1 to 100
      Dim Y as Integer
      Y = X
   Next X
   ’ This line causes an error
End Sub

Visual C#

public void myMethod()
   int X;
   for (X = 1; X < 101; X++)
      int Y;
      Y = X;
   // This line causes an error

Visual Basic allows you to create method variables that are not destroyed after a method finishes execution. These variables, called static method variables, persist in memory and retain their values through multiple executions of a method. You declare a static variable with the Static keyword as follows:

Visual Basic .NET

Public Sub myMethod()
   Static Iterations as Integer
   ’ This variable will be incremented every time this method 
   ’ is run.
   Iterations += 1
End Sub 

Although this variable persists in memory, it is still available only during execution of this method. You would use a Static variable for a method that needed to keep track of how many times it had been called.

This feature is not available in Visual C#, and the Static keyword in C# has a different meaning, which is discussed in Lesson 5 of this chapter.


A method can take one or more parameters. A parameter is an argument that is passed to the method by the method that calls it. Parameters are enclosed in parentheses after the method name in the method declaration, and types must be specified for parameters. Here is an example of a method with parameters:

Visual Basic .NET

Public Sub DisplayName(ByVal name As String, ByVal age As Byte)
   Console.WriteLine("Hello " & name & ". You are " & _
      age.ToString & " years old.")
End Sub

Visual C#

public void DisplayName(string name, byte age)
   Console.WriteLine("Hello " + name + ". You are " + 
      age.ToString() + "years old.");

This method requires two parameters: a String parameter, which is given the local name name, and a Byte parameter, which is given the local name age. These variables have scope only for the duration of the method, and they cannot be used after the method returns. For a further discussion of scope, see Lesson 5 of this chapter.

Parameters can be passed in two ways, by value or by reference. In the .NET Framework, parameters are passed by value by default. By value means that whenever a parameter is supplied, a copy of the data contained in the variable is made and passed to the method. Any changes made in the value passed to the method are not reflected in the original variable. Although it is the default setting, you can explicitly indicate that a variable be passed by value in Visual Basic with the ByVal keyword.

When parameters are passed by reference, on the other hand, a reference to the memory location where the variable resides is supplied instead of an actual value. Thus, every time the method performs a manipulation on that variable, the changes are reflected in the actual object. To pass a parameter by reference in Visual Basic .NET, you use the keyword ByRef. In Visual C#, the keyword ref is used. The following example demonstrates passing parameters by value or by reference:

Visual Basic .NET

Public Sub Demo1()
   Dim x, y As Integer
   x = 15
   y = 20
   ’ This line calls the Demo2 method (see below)
   Demo2(x, y)
   ’ What values will x and y have now?
   MessageBox.Show("X = " & x.ToString & " Y = " & y.ToString)
End Sub
Public Sub Demo2(ByVal p1 As Integer, ByRef p2 As Integer)
   p1 = p1 + p2
   p2 = p2 + p1
End Sub

Visual C#

public void Demo1()
   int x,y;
   x = 15;
   y = 20;
   // This line calls the Demo2 method (see below)
   Demo2(x, ref y);
   // What values will x and y have now?
   System.Windows.Forms.MessageBox.Show("X = " + x.ToString() + 
      " Y = " + y.ToString());
public void Demo2(int p1, ref int p2)
   p1 = p1 + p2;
   p2 = p2 + p1;

In this example, two variables named x and y are created and assigned values. The variables x and y are then passed to the second method. X is passed by value, y is passed by reference, and both are represented in the second method as the variables p1 and p2. Because p1 is passed by value, it represents a copy of the data stored in x, and the manipulations performed on it are for naught. Once the method ends, the variable goes out of scope and its memory is reclaimed. The parameter p2, on the other hand, does not contain a value at all; rather, it contains a reference to the actual data stored in the variable y. Thus, when the line p2 = p2 + p1 is reached, the value stored at the memory location represented by p2 is changed. Therefore, when the final line of the Demo1 method is reached, the value of x will be unchanged at 15, but the value of y will have changed and will be equal to 55.

Note that if your parameter is a reference type, it makes no difference if the parameter is passed by value or by reference—the behavior will be the same. In both cases, any manipulations done on the parameter will be reflected in the object passed as a parameter.

Output Parameters

In Visual C#, you can also use output parameters. This feature is not available in Visual Basic .NET. An output parameter is a parameter that is passed from a called method to the method that called it—that is, in the reverse direction. Output parameters are useful if you want a method to return more than a single value. An output parameter is specified by using the out keyword. Output parameters are always passed by reference and do not need to be initialized before use. The following example demonstrates output parameters:

Visual C#

public void aWord (out string Word)
   Word = "Mambo";
public void ShowWord()
   string Word;
   aWord(out Word);
   Console.Writeline("The word of the day is " + Word);

Here the ShowWord method calls the aWord method with the output parameter Word. The aWord method assigns a value to the output parameter Word, thereby assigning a value to the Word variable.

Optional Parameters

In Visual Basic .NET, you are able to specify optional parameters for your methods. This feature is not available in Visual C#. You specify a parameter as optional using the Optional keyword. Optional parameters must be the last parameters in a method declaration, and you must supply default values for optional parameters. The following example demonstrates the use of optional parameters:

Visual Basic .NET

Public Sub Cook(ByVal time As Integer, Optional ByVal temp As _
   Integer = 350)
   ’ Implementation code goes here
End Sub  

Constructors and Destructors

The constructor is the first method that is run when an instance of a type is created. In Visual Basic, the constructor is always Sub New. In Visual C#, it is a method with the same name as the class. You use a constructor to initialize class and structure data before use. Constructors can never return a value and can be overridden to provide custom initialization functionality. Chapter 4 discusses how to override methods. A constructor can also contain calls to other methods. An example of a constructor follows:

Visual Basic .NET

Public Class aClass
   Public Sub New()
      ’ Class initialization code goes here
   End Sub
End Class

Visual C#

public class aClass
   public aClass()
      // Class initialization code goes here

Similarly, a destructor is the last method run by a class. A destructor (known as a finalizer in Visual Basic) contains code to "clean up" when a class is destroyed. This cleanup might include decrementing counters or releasing resources. A finalizer in Visual Basic .NET is always Sub Finalize(), and a destructor in Visual C# is a method with the same name as the class preceded by a tilde (~). Examples of destructors follow:

Visual Basic .NET

Public Class aClass
   Protected Overrides Sub Finalize()
      ’ Clean up code goes here
   End Sub
End Class

Visual C#

public class aClass
      // Clean up code goes here

In Visual Basic, the finalizer must use the Overrides keyword. The meaning and usage of this keyword is discussed in Chapter 4.

Because garbage collection does not occur in any specific order, it is impossible to determine when a class’s destructor will be called.

Lesson Summary

  • Methods perform the data manipulation that gives classes and structures their associated behavior. Methods can return a value, but they do not have to. In Visual Basic .NET, methods that return values are called Functions, and non-value-returning methods are called Subs. In Visual C#, if a method doesn’t return a value, it has a return type of void. Methods are called by placing the name of the method in the code along with any required parameters.
  • Methods can have parameters, which are values required by the method. Parameters are passed by value by default. You can pass parameters by reference with the ref keyword (Visual C#) or with the ByRef keyword (Visual Basic .NET). For parameters of reference types, the behavior is the same whether passed by value or by reference. Visual C# allows you to specify output parameters from your method. Visual Basic .NET allows you to designate optional parameters.
  • The constructor is the first method called on instantiation of a type. The constructor provides a way to set default values for data or perform other necessary functions before the object is available for use. Destructors are called just before an object is destroyed and can be used to run clean-up code. Since object cleanup is controlled by the common language runtime, you cannot control when a destructor is called.

Lesson 5: Scope and Access Levels

Access levels define how types are instantiated and how members are accessed. You use access levels to encapsulate data and methods in your types, and to expose functionality to outside objects. In this lesson, you will learn how access modifiers control code access and how to use them in your types.

After this lesson, you will be able to

  • Explain the meanings of different access levels and how they affect access to classes, variables, and nested types
  • Explain what scope is and how it affects program execution

Estimated lesson time: 20 minutes

You can control how elements of your application are accessed by using access modifiers. Access modifiers are keywords such as Public (public), Private (private), and Friend (internal) that precede a variable or type declaration. The keyword that is used controls the level of access the member is allowed. When an access modifier precedes a member declaration, it affects the scope of that member, meaning it controls what code can access it. When a modifier precedes a type declaration, it determines both the scope of its members and how that type is instanced.

Member Access Modifiers

Type members can have modifiers to control their scope. Table 1.2 summarizes the different access levels.

Table 1-2  Access Levels

Access ModifierEffect on Members
Public (Visual Basic .NET), public (Visual C#)Can be accessed from anywhere.
Private (Visual Basic .NET), private (Visual C#)Can be accessed only by members within the type that defines it.
Friend (Visual Basic .NET), internal (Visual C#)Can be accessed from all types within the assembly, but not from outside the assembly.
Protected (Visual Basic .NET), protected (Visual C#)Can be accessed only by members within the type that defines it or types that inherit from that type.
Protected Friend (Visual Basic .NET), protected internal (Visual C#)Can be accessed from all types within the assembly or from types inheriting from the owning type. This is the union of Protected (protected) and Friend (internal) access.

Any member with the Public (public) modifier is visible to all code outside the class. Thus, other objects can access and modify public fields and can call public methods. Conversely, Private (private) methods are visible only inside the type to which they belong and cannot be accessed from the outside. A third access modifier, Friend (internal), indicates that members can be accessed by other types in the same assembly but cannot be accessed from types outside the assembly. The Protected (protected) modifier allows access from within the type to which the member belongs and to any types that inherit that type. The Protected Friend (protected internal) level provides the union of Protected (protected) and Friend (internal) access. For member variables, the access modifier can replace the Dim statement. If the Dim statement is used (in Visual Basic .NET) or no access modifier is used (in Visual C#), the variable is considered private in Visual C# and Visual Basic .NET classes, Public in Visual Basic .NET structures, and private in Visual C# structures. Methods do not require an access modifier. If no access modifier is specified, the method is Private (private) by default in a class or structure in C#, and Public (public) in a class or structure in Visual Basic .NET.

Inheritance is discussed in depth in Chapter 4.

The following example demonstrates how to use the access modifiers and illustrates how they control access:

Visual Basic .NET

Public Class aClass
   ’ This field can be accessed unconditionally by external
   ’ code
   Public anInteger As Integer
   ’ This method can be called by members of this class and
   ’ assembly, but not by external code
   Friend Sub myMethod()
   End Sub
   ’ This field can only be accessed by members of this class
   Private aString As String
   ’ This method may be called by members of this class and any 
   ’ inheriting classes 
   Protected Function Return1() As Integer
      Return 1
   End Function
   ’ This field may be accessed by members of the assembly or
   ’ inheriting classes
   Protected Friend aLong As Long
End Class

Visual C#

public class aClass
   // This field can be accessed unconditionally by external
   // code
   public int anInteger;
   // This method can be called by members of this class and
   // assembly, but not by external code
   internal void myMethod()
   // This field can only be accessed by members of this class
   private string aString;
   // This method may be called by members of this class and 
   // any inheriting classes 
   protected int Return1()
      return 1;
   // This field may be accessed by members of the assembly or
   // inheriting classes
   protected internal long aLong;

Type Access Modifiers

Structures and classes can also have access modifiers. Access modifiers control how a type can be instantiated and are similar to access modifiers for members. A Public (public) class can be instantiated by any object in the application. A Friend (internal) class can be created by other members of the assembly but cannot be created by objects external to the assembly. The Private (private) and Protected (protected) modifiers can be used only on nested types. A private class can be created only by objects of its own type or by types in which it is nested. Nested types also can be Protected (protected) or Protected Friend (protected internal), which allows classes inheriting the parent class to have access to them. Protected Friend (protected internal) classes are also visible to other members of the namespace. If no access modifier is specified for a class or a structure, it is considered Public (public).

Protected members are discussed in greater detail in Chapter 4.

Access Modifiers for Nested Types

In general, a nested type is a type that is used exclusively by the type that contains it. Thus, it is usually a good practice to assign the Private (private) access modifier to a nested type. Under rare circumstances, you might want to create a nested type that can be created by other types and assign it a different access modifier. Although you can assign any access modifier to a nested type, the behavior will never be greater than the access modifier of the type that contains it. Consider the following example:

Visual Basic .NET

Friend Class ParentClass
   Public Class NestedClass
   End Class
End Class

Visual C#

internal class ParentClass
   public class NestedClass

In this example, the nested class is declared Public (public) but is contained within a class that is marked Friend (internal). Although the nested class is public, it will not be visible to any classes outside the assembly by virtue of the parent class being marked Friend (internal). Thus, the nested class has a practical access level of Friend (internal).

Shared (static) Members

Regular members are unique to each object instance as shown in the following pseudocode:

Visual Basic .NET

Dim Object1 as New DemoClass()
Dim Object2 as New DemoClass()
Object1.MyField = 15
Object2.MyField = 20

Visual C#

DemoClass Object1 = new DemoClass();
DemoClass Object2 = new DemoClass();
Object1.MyField = 15;
Object2.MyField = 20;

The MyField field holds a different value, depending on which instance of the class is referenced. It is also possible to have members that are common to all instances of a class. These members are called Shared (static) members. Only one instance of a Shared or static member can exist, no matter how many instances of a particular type have been created.

You can create a Shared (static) field by using the Shared (Visual Basic .NET) or static (Visual C#) keyword. For example:

Visual Basic .NET

Public Class Demo
   Public Shared MyField As Integer
End Class

Visual C#

public class Demo
   public static int MyField;

Even though multiple instances of the Demo class might be instantiated, there will be only one copy of the MyField field. Note that the Shared (static) keyword is not an access modifier; rather, it specifies the member’s shared nature. Shared members can still be Public (public), Private (private), Friend (internal), and so on.

Methods can be shared as well as fields. Whereas regular methods belong to instances of types, shared methods belong to the type itself. Because shared methods belong to the type itself, they cannot access instance data from any objects. They can only utilize shared variables, variables declared within the method, or parameters passed into the method.

Accessing Shared Members

Because Shared members belong to the type but not to object instances of a type, they should be accessed using the class name rather than the instance name. Although Visual Basic .NET allows you to access Shared members through the object, there is still only one instance of the Shared members. Visual C# is stricter in this regard and does not allow you to access static members through an object instance. An example is shown in the following code sample:

Visual Basic .NET

‘ This example uses the Demo class from the previous example
Dim Object1 as New Demo()
‘ This is incorrect syntax. You should not access shared
‘ members through the object name, though it will not cause an
‘ error.
Object1.MyField = 15
‘ This syntax is correct-accessing the field through the class
‘ instead of the object.
Demo.MyField = 15

Visual C#

// This example uses the Demo class from the previous example
Demo Object1 = new Demo();
// This is incorrect syntax. You cannot access shared
// members through the object name with Visual C#
Object1.MyField = 15;
// This syntax is correct-accessing the field through the class
// instead of the object.
Demo.MyField = 15;

Because Shared members belong to the type instead of any one instance of a type, it is not necessary to instantiate a type before accessing Shared members. Thus, you can call shared methods or retrieve shared fields before an instance of a type exists.

Lesson Summary

  • Access modifiers are used to control the scope of type members. There are five access modifiers: Public (public), Friend (internal), Private (private), Protected (protected), and Protected Friend (protected internal). Each provides varying levels of access.
  • If an access modifier is not specified for a method, it has a default access level of private in Visual C# classes and structures and public in Visual Basic .NET classes and structures. If an access modifier is not specified for a member variable, it has a default access level of private in a class or public in a structure.
  • Access modifiers also can be used on types to control how a type is instantiated. Access levels for types are as follows: Public (public) types can be instantiated from anywhere. Friend (internal) types can be instantiated only by members of the assembly, and Private (private) types can be instantiated only by themselves or within a containing type.
  • If no access modifier is specified for a class or a structure, it is considered Public (public).
  • Nested types obey the same rules as non-nested types, but in practice, they can never have an access level greater than that of their parent type.
  • Shared (static) members belong to the type but not to any instance of a type. They can be accessed without creating an instance of the type and are accessed using the type name instead of the instance name. Shared methods cannot refer to any instance data.

Lesson 6: Garbage Collection

The automatic memory management scheme employed by the .NET Framework is called garbage collection. Memory from objects that are no longer used is traced and reclaimed without any action required by the application. In this lesson, you learn how garbage collection works.

After this lesson, you will be able to

  • Describe how garbage collection manages the reclamation of unused memory
  • Describe how garbage collection deals with circular references

Estimated lesson time: 15 minutes

The .NET Framework employs automatic memory management, which means that when an object is no longer being used, the .NET Framework automatically reclaims the memory that was being used by that object. This process is called garbage collection. Consider the following example:

Visual Basic .NET

Sub GarbageCollectionExample1()
   Dim myWidget As New Widget()
End Sub

Visual C#

void GarbageCollectionExample1()
   Widget myWidget = new Widget();

When this procedure ends, the variable myWidget goes out of scope and the object it refers to is no longer referenced by any application variable. The garbage collector continuously traces the reference tree in the background and identifies objects that no longer have references. When it finds one, such as the Widget in the previous example, it deletes it and reclaims the memory. Because the garbage collector is always running, you do not have to explicitly destroy objects when you are finished with them.

The garbage collector is a low-priority thread under normal circumstances. It operates when processor time is not consumed by more important tasks. When memory becomes limited, however, the garbage collector thread moves up in priority. Memory is reclaimed at a more rapid pace until it is no longer limited, at which point the priority of garbage collection is again lowered.

This non-deterministic approach to memory reclamation seeks to maximize application performance and supplies a less bug-prone application environment. There is a cost, however. Because of the mechanism by which garbage collection operates, you cannot be certain when an object will be reclaimed. Thus, you have no control over when a class’s destructor (Visual C#) or finalizer (Visual Basic .NET) is executed. These methods should not contain code that you rely on being run at a given time. Instead, classes that appropriate expensive resources usually implement a Dispose() method to explicitly free those resources when the class is no longer needed.

Circular References

Garbage collection also manages circular references, previously a common form of memory leak. Consider the following example:

Visual Basic .NET

Class Widget
   Public ChildWidget As Widget
   Public Parent As Widget
End Class
Class aClass
   Public GrandParent As Widget
   Sub Demo()
      Dim Parent As Widget
      Dim Child As Widget
      GrandParent = New Widget()
      GrandParent.ChildWidget = New Widget()
      Parent = GrandParent.ChildWidget
      Parent.ChildWidget = New Widget()
      Child = Parent.ChildWidget
      Child.Parent = Parent
      GrandParent = Nothing
   End Sub
End Class

Visual C#

class Widget
   public Widget ChildWidget;
   public Widget Parent;
class aClass
   Widget GrandParent;
   void Demo()
      Widget Parent;
      Widget Child;
      GrandParent = new Widget();
      GrandParent.ChildWidget = new Widget();
      Parent = GrandParent.ChildWidget;
      Parent.ChildWidget = new Widget();
      Child = Parent.ChildWidget;
      Child.Parent = Parent;
      GrandParent = null;

The Widget class consists of two fields: a ChildWidget field that holds a reference to a Widget object and a Parent field that holds a reference to another Widget object. In this example, a Widget object is created and assigned to the variable GrandParent. This object then spawns another Widget object and assigns it to its ChildWidget field. The Parent variable is also assigned to point to this object. Parent, in turn, creates a third Widget, which is assigned to both the ChildWidget field of Parent and to the Child variable. The Parent field of the Child variable is assigned to Parent, thus creating a reference from Child to Parent. When the GrandParent variable is set to nothing, the Widget objects represented by Parent and Child are left referring only to each other—a circular reference.

Although circular references can create difficult-to-locate memory leaks in other development platforms, the .NET Framework garbage collector is able to trace and remove such memory leaks. Thus, if a pair of objects are only referenced by each other, they will be marked for garbage collection.

Lesson Summary

  • The .NET Framework provides automatic memory reclamation through the garbage collector. The garbage collector is a low-priority thread that always runs in the background of the application. When memory is scarce, the priority of the garbage collector is elevated until sufficient resources are reclaimed.
  • Because you cannot be certain when an object will be garbage collected, you should not rely on code in finalizers or destructors being run within any given time frame. If you have resources that need to be reclaimed as quickly as possible, provide a Dispose() method that gets called explicitly.
  • The garbage collector continuously traces the reference tree and disposes of objects containing circular references to one another in addition to disposing of unreferenced objects.

Lab 1: Classes and Garbage Collection

In this lab, you will practice creating classes and members, and you will create a demonstration of how garbage collection automatically manages memory. You will create a class that interacts with a pre-made user interface. This class will have a shared variable that keeps track of the number of instances that currently exist in memory. Additionally, you will add code to the constructor and destructor of this class to increment and decrement this variable. You will then create multiple instances of this class and watch as their memory is reclaimed by garbage collection. The solution to this lab is available in the \Labs\Ch01\Solution folder on the Supplemental Course Materials CD-ROM.

For this and all of the labs in this book, you will find Visual Basic .NET and Visual C# solutions in their respective folders in \Labs\Chxx\Solutions, where xx stands for the appropriate chapter number.

Before You Begin

There are no prerequisites to complete this lab.

Estimated lesson time: 20 minutes

Exercise 1.1: Making the Demo Class

In this exercise, you will create the Demo class that interacts with the DemoTest project. The DemoTest project is available in the \Labs\Ch01\Partial folder on the Supplemental Course Materials CD-ROM.

To make the Demo class

  1. Open the DemoTest.sln solution in \Labs\Ch01\Partial. This solution contains all of the front-end code you will need for your project.
  2. From the Project menu, choose Add Class.
  3. In the Add New Item dialog box, name your class Demo.
  4. Add a public, shared field named Instances to Demo. This field will track the number of instances of Demo that are currently in memory. The following line shows an example:
  5. Visual Basic .NET

    Public Shared Instances As Long

    Visual C#

    public static long Instances;

  6. Create a constructor for this class (Visual Basic .NET), or add to the default constructor created by Visual Studio (Visual C#). In the constructor, you will add code to increment the Instances variable. The following code shows an example:
  7. Visual Basic .NET

    Public Sub New()
       Instances += 1
    End Sub

    Visual C#

    public Demo()

  8. Create a destructor (finalizer) for this class. In the destructor, add code to decrement the Instances variable. For example:
  9. Visual Basic .NET

    Protected Overrides Sub Finalize()
       Instances -= 1
    End Sub

    Visual C#


    In Visual Basic .NET, you must use the Overrides keyword in the finalizer. The meaning and use of the Overrides keyword is discussed in Chapter 4.

  10. From the File menu, choose Save All to save your work.

Exercise 1.2: Demonstrating Garbage Collection

The front end provided in the DemoTest project contains a form that displays two controls: a button and a label. Additionally, there is an invisible timer component that updates the label control every second. You will run the application and observe how instances of your class are created and garbage collected.

To create the garbage collection demo

  1. In the Designer, examine Form1. You can open the designer by double-clicking Form1 in Solution Explorer. Note that it has a Button control, a Label control, and a Timer component in the component tray.

  2. NOTE:
    Controls are examined further in Chapter 2.

  3. Double-click the Button to open the code window to the click event handler.
  4. Find Private Sub Button1_Click (Visual Basic .NET) or private void button1_Click (Visual C#). Add the following code:
  5. Visual Basic .NET

    Dim Counter As Integer
    Dim aDemo
    For Counter = 1 to 1000
       aDemo = New Demo()

    Visual C#

    int Counter;
    Demo aDemo;
    for (Counter = 0; Counter < 1000; Counter++)
       aDemo = new Demo();

    This code declares two variables, a Counter and a variable of the Demo class. It then enters an iteration loop. One thousand loops are iterated, and in each loop, the aDemo variable is assigned to a new instance of the Demo class. Recall that creating a new instance of Demo will cause the class’s constructor to execute, incrementing the shared variable Instances. As the loop ends and restarts, the aDemo variable is assigned to another new instance of Demo, and all the references to the previous instance of the Demo class are released, thus marking the class for garbage collection. This loop will execute 1000 times for every click of the button.

  6. Press F5 to build and run your application. You should see a button and a label indicating how many instances of Demo exist in memory. Click this button once.
  7. The label now reads "There are 1000 instances of Demo in memory". Wait for a while. After a measurable interval, perhaps even as long as a couple minutes, the label will indicate zero instances again, indicating that the 1000 instances of Demo have been garbage collected and their destructors executed, decrementing the Instances variable.

    The label did not revert instantly because garbage collection is a relatively low-priority thread under normal circumstances. However, when memory gets scarce, the priority of the thread is increased.

  8. Click the button several times in succession. See how many instances you can put into memory. If your machine has a large amount of memory, you might be able to create tens of thousands of instances before garbage collection is performed. Once memory gets scarce, though, garbage collection rapidly and efficiently reclaims the memory used by these unreferenced objects.


The following review questions are intended to reinforce key concepts and information presented in this chapter. If you are unable to answer a question, return to the appropriate lesson and review, and then try the lesson again. Answers to the questions can be found in Appendix A.

  1. Briefly describe the major components of the .NET Framework, and describe what each component does.
  2. Briefly explain what is meant by a reference type and a value type.
  3. How do you enable your application to use .NET base class library members without referencing their fully qualified names?
  4. Briefly describe how garbage collection works.
  5. Briefly describe what members are, and list the four types of members.
  6. Explain what constructors and destructors are, and describe their use.
  7. Briefly explain the difference between Public (public), Friend (internal), and Private (private) access levels as they apply to user-defined types and members.
  8. Do you need to instantiate a class before accessing a Shared (static) member? Why or why not?
  9. Briefly describe how a class is similar to a structure. How are they different?

Meet the Author

Matthew Stoecker, MCP, has written numerous books and articles on Microsoft Visual Basic, Visual C#, Windows Forms, and Windows Presentation Foundation, including the SELF-PACED TRAINING KITS for Exams 70-511, 70-505, and 70-502.

Developed by senior editors and content managers at Microsoft Corporation.

Customer Reviews

Average Review:

Write a Review

and post it to your social network


Most Helpful Customer Reviews

See all customer reviews >