You are on page 1of 29

Color profile: Generic CMYK printer profile

Composite DefaultAll-In-One
screenAll-In-One
/ MCAD/MCSD
/ MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Strings, Exceptions,
and Events
CHAPTER

4
In this chapter, you will
• Learn about the string class
• Explore arrays
• Manipulate collections
• Learn the purpose of exception handling
• Be introduced to the System.Exception class
• Get acquainted with try and catch blocks
• Learn how to use the finally statement
• Create your own exception classes
• Get to understand the event-handling mechanism in the .NET Framework

The information in this chapter is included for background. If you already understand
the subjects listed, you can go on to Chapter 5 and the Visual Studio .NET development
environment.

This chapter will explain three concepts that are used throughout the .NET develop-
ment environment. We’ll look at the string class and how to use it, along with collec-
tions and arrays. We will also look at the concept of exception handling, which takes
care of those pesky runtime errors. The final topic in this chapter is the event-handling
environment in the .NET Framework.

The String Class


The C# language uses the string data type as if it were a primitive data type, but it is really a
very functional data type that has no relation to any of the primitives. The string data type
is a C# keyword that refers to the System.String class. The System.String class is
not the only class in the .NET Framework that provides string-related functionality, how-
ever. We will start by investigating the System.String class, we will also look at the
System.Text and System.Text.RegularExpressions namespaces. The
System.Text.StringBuilder class that is used to build strings, as well as the
Console.Write and Console.WriteLine to format strings are introduced. We will
also touch on regular expressions, which are used to manipulate strings.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:23 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


2
System.String
The System.String class is the class most commonly used to represent strings. The
class stores a string and provides a large number of operations that can be performed on
that string. Unlike other classes, System.String has its own keyword and syntax to
make it simple to create and manipulate string data. The string keyword is used when
referring to the System.String class. We do not create strings using the new key-
word—we declare them as if they were primitives.
The following example shows how strings are created, and how more string data is
appended to them:

string str; //Declare the string


str = "No man is an island"; //Assign a string of characters to str
str += ", wrote John Donne"; //concatenate to the original string
string r = str + "!"; //create a new string from the old

An instance of a string is said to be immutable because its value cannot be modified


once it has been created. Methods that appear to modify a string actually return a new
string containing the modification. In the third line of the preceding example, the string
str is “modified” by concatenating some additional data, but what actually happens is
that a new string is created and the reference str is assigned that new instance. The old
string will be cleaned out by the garbage collector.
There are a lot of members in the string class that are used to manipulate strings;
Table 4-1 lists the common members.

Member Description
Chars Gets the character at a specified character position in this instance
Clone Returns a reference to this instance of String
Compare Compares two specified string objects
Concat Concatenates one or more instances of string, or the string
representations of the values of one or more instances of Object
Copy Creates a new instance of String with the same value as a
specified string
CopyTo Copies a specified number of characters from a specified position in this
instance to a specified position in an array of Unicode characters
EndsWith Determines whether the end of this instance matches the specified string
Equals Determines whether two string objects have the same value (overridden)
Format Replaces each format specification in a specified string with the textual
equivalent of a corresponding object’s value
GetEnumerator Retrieves an object that can iterate through the individual characters in
this instance
GetHashCode Returns the hash code for this instance
GetType Gets the Type of the current instance
Table 4-1 Members of System.String

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


3
Member Description

PART I
GetTypeCode Returns the TypeCode for class String
IndexOf Reports the index of the first occurrence of a string, or of one or more
characters, within this instance
IndexOfAny Reports the index of the first occurrence in this instance of any character
in a specified array of Unicode characters
Insert Inserts a specified instance of string at a specified index position in
this instance
Intern Retrieves the system’s reference to the specified string
IsInterned Retrieves a reference to a specified string
Join Concatenates a specified separator string between each element of a
specified string array, yielding a single concatenated string
LastIndexOf Reports the index position of the last occurrence of a specified Unicode
character or string within this instance
LastIndexOfAny Reports the index position of the last occurrence in this instance of one
or more characters specified in a Unicode array
Length Gets the number of characters in this instance
PadLeft Right-aligns the characters in this instance, padding on the left with spaces
or a specified Unicode character for a specified total length
PadRight Left-aligns the characters in this string, padding on the right with spaces
or a specified Unicode character, for a specified total length
Remove Deletes a specified number of characters from this instance, beginning at a
specified position
Replace Replaces all occurrences of a specified Unicode character or string in this
instance with another specified Unicode character or string
Split Identifies the substrings in this instance that are delimited by one or
more characters specified in an array, and then places the substrings
into a string array
StartsWith Determines whether the beginning of this instance matches the
specified string
Substring Retrieves a substring from this instance
ToCharArray Copies the characters in this instance to a Unicode character array
ToLower Returns a copy of this string in lowercase
ToString Converts the value of this instance to a string
ToUpper Returns a copy of this string in uppercase
Trim Removes all occurrences of a set of specified characters from the
beginning and end of this instance
TrimEnd Removes all occurrences of a set of characters specified in a Unicode
character array from the end of this instance
TrimStart Removes all occurrences of a set of characters specified in a Unicode
character array from the beginning of this instance
Table 4-1 Members of System.String (continued)

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


4
String Building
As you learned in the previous section, strings are immutable objects, meaning that a
string cannot be modified; instead we get an entirely new string when we modify the
original. Consider the following lines of code:

string strOne = "This is the first string's data";


strOne += " and this is the second part!";

The result of these two lines is that we have a string object on the heap containing
"This is the first string's data", and the reference on the stack (strOne) is
assigned to the string object. After the second line of code, there is a change: the origi-
nal string object is still on the heap, and it is unchanged. A new string object has
been created containing "This is the first string's data and this is
the second part!". The reference (strOne) is now assigned to the new string
object, and the first string object will be cleared away by the garbage collector.
Immutable strings are very efficient when it comes to manipulating strings of known
length, but they suffer when the length of the string changes. For example, let’s take our
earlier code and perform that old children’s cipher on the text by shifting every letter two
characters back in the alphabet; e becomes c, and so on. For example, “Hello World” will
be turned into “Fcjjm Umpjb”.

// String.cs
using System;

public class MainClass


{
public static void Main()
{
string strHello = "Hello World!";
for (int i = (int)'a'; i<=(int)'z'; i++)
{
char chOld = (char)i;
char chNew = (char)(i-2);
strHello = strHello.Replace(chOld, chNew);
}
for (int i = (int)'A'; i<=(int)'Z'; i++)
{
char chOld = (char)i;
char chNew = (char)(i-2);
strHello = strHello.Replace(chOld, chNew);
}
Console.WriteLine("Child version: /n" + strHello);
}
}

This program produces a large number of new string objects because each time we
call the Replace() method, a new object will be constructed. This example highlights
the need for another string-like class—the System.Text.StringBuilder class.
The System.Text.StringBuilder class produces a mutable object whose mem-
ory allocation we can control by adding and removing space from the object. Let’s start
by rewriting the preceding example using the System.Text.StringBuilder class:

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


5
// StringBuilder.cs
using System;

PART I
using System.Text;

public class MainClass


{
public static void Main()
{
StringBuilder strHello = new StringBuilder("Hello World!", 30);
for (int i = (int)'a'; i<=(int)'z'; i++)
{
char chOld = (char)i;
char chNew = (char)(i-2);
strHello = strHello.Replace(chOld, chNew);
}
for (int i = (int)'A'; i<=(int)'Z'; i++)
{
char chOld = (char)i;
char chNew = (char)(i-2);
strHello = strHello.Replace(chOld, chNew);
}
Console.WriteLine("Child version: /n" + strHello.ToString());
}
}

With some very small changes, we have altered the processing to create only one object—
the StringBuilder object—constructed by using the new keyword and specifying an
initial length of 30 characters.
You will normally use the StringBuilder class to perform string manipulations
on strings that are used for display purposes. Table 4-2 lists the members of the
StringBuilder class.

Member Description
Append Appends the string representation of a specified object to the end of
this instance
Capacity Gets or sets the maximum number of characters that can be contained in
the memory allocated by the current instance
Chars Gets or sets the character at the specified character position in this instance
EnsureCapacity Ensures that the capacity of this instance of StringBuilder is at least
the specified value
Equals Returns a value indicating whether this instance is equal to a specified object
GetHashCode Serves as a hash function for a particular type, suitable for use in hashing
algorithms and data structures like a hash table
GetType Gets the Type of the current instance
Insert Inserts the string representation of a specified object into this instance at a
specified character position (this is an overloaded method)
Length Gets or sets the length of this instance
MaxCapacity Gets the maximum capacity of this instance
Remove Removes the specified range of characters from this instance
Replace Replaces all occurrences of a specified character or string in this instance
with another specified character or string
ToString Converts a StringBuilder to a string
Table 4-2 The Members of the StringBuilder Class

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


6
String Formatting
The output of strings or any data onto the screen sometimes produces unwanted effects
or, indeed, almost incomprehensible effects. Take the formatting of dates as an exam-
ple. Dates are formatted differently in different countries (and sometimes in different
parts of a country). In the United States, the date 02/10/02 would translate to February
10, 2002, while in Canada it could mean October 2, 2002—that difference alone makes
the date format problematic. The date format used in a specific location is part of that lo-
cation’s locale (sometimes called culture), and taking advantage of the locale and making
applications truly international is the topic of Chapter 7—for now we simply need to
understand that there is an issue to be addressed.
C# has the ability to use the client’s locale to present the date in the right format for
that user. Similar issues apply to currency ($, €, or SKR) as well as how the boundary
between the integral and decimal part of a number is marked—in the English-speaking
world, the period (3.141592653) is almost always used to mark the separation, while in
the French, Spanish-speaking, and Swedish cultures the comma (3,141592653) is used.
In the next example, we will print out a formatted string with some numbers in it to
demonstrate how number formatting is controlled by using formatting qualifiers.

// StringFormat.cs
using System;

public class MainClass


{
public static void Main()
{
double PI = 3.14159;
int i = 42;

Console.WriteLine("The double is {0,10:E} and the int contains {1}", PI, i);
}
}

The output from this program can be seen in Figure 4-1. The formatting inserted in
the string is used to make the numbers print in a predetermined way: {0,10:E} speci-
fies that the first (zero-based) parameter following the formatting string will be printed
in a field of 10 characters using scientific format. The second format, {1}, takes the sec-
ond parameter and prints it using the default settings.

Arrays
The array is one of the most common concepts used when storing a series of data points,
either in a one-dimensional or multidimensional format. C# implements arrays as a
class, and the arrays can hold data of one type (such as int, double, long, and so on).
It also lets you create arrays of any number of dimensions.
You were already introduced to arrays in Chapter 2, and here we are going to look
more closely at the Array class and see how we can take advantage of it.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


7

PART I
Figure 4-1 The output of the string formatting program

The System.Array Class


The array in C# uses the System.Array class, which provides many members to
manipulate the resulting array, as well as the option to create multidimensional arrays.
Table 4-3 lists the members of the Array class.
The following example uses some of the methods and properties from Table 4-3 to
show their use:

// Array.cs
using System;
class ArrayTest
{
static public void Main()
{
// Declare some arrays
int[] Ints;
Ints = new int[10]; //create an int array with 10 members
for (int i=0; i<Ints.Length; i++)
{
Ints[i] = i;
}
int[] Instr = new int[10];
//Copy Ints to Instr
Array.Copy( Ints, Ints.GetLowerBound(0), Instr,
Instr.GetLowerBound(0), 10 );
// Reverse the content of Instr
Array.Reverse(Instr);

Console.Write("The initial Array has the following members : ");


for (int i=0; i < Ints.Length;i++)
{

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:24 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


8
Console.Write(Ints[i]);
}
Console.Write("\n\nThe reverse Array has the following members : ");
for (int i=0; i < Instr.Length;i++)
{
Console.Write(Instr[i]);
}
//Sort the Instr Array
Array.Sort(Instr);
Console.Write("\n\nThe reverse sorted Array has the following members : ");
for (int i=0; i < Instr.Length;i++)
{
Console.Write(Instr[i]);
}
}
}

Member Description
Clear Sets a range of elements in the array to zero, to false, or to a null
reference, depending on the element type
Clone Creates a shallow copy of the array—a shallow copy will only copy the
values or references that are in the original array, not the physical objects
Copy Copies a section of one array to another array and performs type casting
and boxing as required
CopyTo Copies all the elements of the current one-dimensional array to the specified
one-dimensional array starting at the specified destination array index
Equals Determines whether two Object instances are equal
GetLength Gets the number of elements in the specified dimension of the array
GetLowerBound Gets the lower bound of the specified dimension in the array
GetType Gets the Type of the current instance
GetUpperBound Gets the upper bound of the specified dimension in the array
GetValue Gets the value of the specified element in the current array
IndexOf Returns the index of the first occurrence of a value in a one-dimensional
array or in a portion of the array
Initialize Initializes every element of the value-type array by calling the default
constructor of the value type
IsFixedSize Gets a value indicating whether the array has a fixed size
IsReadOnly Gets a value indicating whether the array is read-only
Length Gets the total number of elements in all the dimensions of the array
Rank Gets the rank (number of dimensions) of the array
Reverse Reverses the order of the elements in a one-dimensional array or in a
portion of the array
Sort Sorts the elements in one-dimensional array objects
ToString Returns a string that represents the current Object
Table 4-3 The Members of the System.Array Class

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:25 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


9
In the preceding program you can see the use of Reverse and Sort. The output will
be as follows:

PART I
The initial Array has the following members : 0123456789
The reverse Array has the following members : 9876543210
The reverse sorted Array has the following members : 0123456789

Collections
A different way of storing items is to use the OO concept of a collection, which you were
introduced to in Chapter 3. We will now look at the support for this OO concept in C#.
A collection is defined as a set of similarly typed objects that are grouped together,
similar to an array, but built to store objects. The .NET Framework support for collec-
tions is provided through the System.Collections namespace. Table 4-4 lists the
collections defined in that namespace.

Class Description
ArrayList Implements the IList interface using an array
whose size is dynamically increased as required
BitArray Manages a compact array of bit values, which are
represented as Booleans, where true indicates
that the bit is on (1), and false indicates the bit
is off (0)
CaseInsensitiveComparer Compares two objects for equivalence, ignoring
the case of strings
CaseInsensitiveHashCodeProvider Supplies a hash code for an object, using a hashing
algorithm that ignores the case of strings
CollectionBase Provides the abstract base class for a strongly
typed collection
Comparer Compares two objects for equivalence, where
string comparisons are case-sensitive
DictionaryBase Provides the abstract base class for a strongly
typed collection of key-and-value pairs
Hashtable Represents a collection of key-and-value pairs that
are organized based on the hash code of the key
Queue Represents a first-in, first-out collection of objects
ReadOnlyCollectionBase Provides the abstract base class for a strongly
typed read-only collection
SortedList Represents a collection of key-and-value pairs
that are sorted by the keys and are accessible by
key and by index
Stack Represents a simple last-in, first-out collection
of objects
Table 4-4 The Classes in the System.Collections Namespace

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:25 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


10
The following example illustrates the use of the SortedList class to store string
objects:

using System;
using System.Collections;
public class ExampleSortedList
{

public static void Main()


{

// Creates and initializes a new SortedList.


SortedList slOne = new SortedList();
slOne.Add("First", "Hello");
slOne.Add("Second", "World");
slOne.Add("Third", "!");

// Displays the properties and values of the SortedList.


Console.WriteLine( "slOne" );
Console.WriteLine( " Count: {0}", slOne.Count );
Console.WriteLine( " Capacity: {0}", slOne.Capacity );
Console.WriteLine( " Keys and Values:" );
WriteKeysAndValues( slOne );
}
public static void WriteKeysAndValues( SortedList sList )
{
Console.WriteLine( "\t-KEY-\t-VALUE-" );
for ( int i = 0; i < sList.Count; i++ )
{
Console.WriteLine( "\t{0}:\t{1}", sList.GetKey(i), sList.GetByIndex(i) );
}
Console.WriteLine();
}
}

The output from the preceding example code is as follows:

slOne
Count: 3
Capacity: 16
Keys and Values:
-KEY- -VALUE-
First: Hello
Second: World
Third: !

Overview of Exception Handling


If you consider any application, you can probably think of a number of things that can
go wrong with it. Suppose you ask the user to enter a number into your program, and
then you store that number in an integer variable—it’s possible that the user will give
you a number that exceeds the boundaries of the integer type. Another possibility is that
a user gives your program a filename to work with, and when the program looks for the

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:25 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


11
file, it can’t be found. These types of errors are unavoidable; they happen frequently and
must be dealt with properly.

PART I
Note that we are not talking about errors that can and should be avoided. You don’t
want to write complicated exception handling for an error such as division by zero,
which you shouldn’t let happen. Along the same lines, there is no point in “handling”
an error that occurs because your program tried to add an element to an array beyond
the array boundaries. These are program bugs, and they should be fixed before the pro-
gram is considered complete. Don’t make the mistake of creating error-handling rou-
tines for these kinds of errors.
An exception handler is a piece of code that handles the first kind of error—those that
cannot be avoided. When a program is asked to look for a file that is not there, the pro-
gram code that looks for files causes an exception object to be “thrown.” This means that
it creates an object (in this case, an object of type FileNotFoundException) and
then searches for code that will deal with the error. If it doesn’t find the code in the cur-
rent method, program execution returns to the caller of the method and searches there.
This search continues (in a process called unwinding the call stack) until either the error is
handled or the Main() method is entered. If the error flows back through all the calling
methods and is not handled anywhere (including in Main()), the error is “caught” by
the .NET runtime. This is not good news, since it means that the user of your program
will be presented with a dialog box that essentially says your program bombed out.
By using the techniques described in this chapter for handling errors, you will achieve
the following:

• Take advantage of an OO approach. One of the goals of OOP is to have loosely


coupled objects, meaning that one object should not rely heavily on another
object. By decoupling the logic of the program from the logic of error handling,
you will achieve good OO design.
• Make use of an object to describe or explain an error. You can create
your own exception objects from class files that you build. These objects
can have properties that describe the error and methods that will display
meaningful messages.
• Eliminate duplicate code. Very often, we must code the same thing over and
over again, in order to achieve proper error handling. By placing all of the code
in a single object, we are able to write once, use many times, another OOP goal.

Throwing and Catching Exceptions


The process of creating a new error object when a particular condition occurs is called
throwing an exception. For example, upon dividing by zero, the CLR causes an exception
object (of type System.DivideByZeroException) to be thrown and then looks for
a handler (code that catches the exception). In the following example, there is no handler

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:25 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


12
to catch the error, so the CLR displays the dialog box shown in Figure 4-2 to the user of
the program, and then causes the program to end.

public class DivideByZero


{
public static void Main()
{
int x = 0;
int y = 10;
int z = y / x;
System.Console.WriteLine ("We'll never get here in the code.");
}
}

Coding to Handle Errors and Exceptions


There are three types of code blocks that you can use to test, catch, and handle runtime
errors:

• try block This tells the CLR that we know an exception might occur in
the code.
• catch block This is the block of code that tells the CLR what to do if a
specific exception has occurred.
• finally block This is the last piece of code to be executed, whether an
exception occurred or not.

Before we examine each of these blocks in detail, take a moment to look at the following
sequence of events that will take us through the steps of how the exception handling
flows:

1. Program execution enters a try block. Each line of code is executed. If no error
occurs, control is transferred to the nearest finally block (Step 4 in this list).
If no finally block exists, execution continues on the instruction following
the last catch block.
2. If an error occurs, the CLR creates an object to represent the error and transfers
execution control to the catch blocks. Each catch block is examined, in

Figure 4-2
The dialog box
presented to the
user before the
program closes

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:25 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screenAll-In-One
/ MCAD/MCSD
/ MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


13
order of appearance. If a catch block is found that deals with the error object,
the code within that block is executed and control is then transferred to the

PART I
finally block (step 4 in this list).
3. If no catch block is found that handles the error object, the CLR passes the
error object to the caller of the current method. The process described in step 2
continues in the caller method. Again, if no catch block is found, the error is
passed back until it reaches the Main() method. Once in Main(), the error
is either “caught” or it causes the program to terminate prematurely and it
displays a dialog box like the one shown earlier in Figure 4-2.
4. The finally block is executed. Notice that we do not mention any conditions
on this block of code executing. This is because you are guaranteed (unless
some abnormal abort like a power failure or a kernel abort occurs) that the
finally block of code will run, whether there was an error or not.

In the following sections, we will examine the use of the try and catch blocks and
then look at the benefits of coding a good finally block. We will also explore the
System.Exception class and its children in order to understand the types of excep-
tions that may occur.

The try … catch Block


If you suspect that your code may cause an exception to be thrown, you can first place that
code within a try block. True to its name, it tells the compiler to try the code and, if an
error occurs, exit from the block and check for a catch block that handles the error. If we
recode our DivideByZero example and use a try block, we can handle the error with-
out the user getting involved at all.

public class DivideByZeroHandled


{
public static void Main()
{
try
{
int x = 0;
int y = 10;
int z = y / x;
System.Console.WriteLine ("We'll never get here in the code.");
} catch (System.Exception e)
{
System.Console.WriteLine ("We caught an error!");
// write code to handle the error here
}
System.Console.WriteLine ("We will now get to the end of the code!");
}
}

Here we’ve told the CLR to try to execute the code in the try block. Of course, we
know that the division by zero will cause an error. The CLR will then create an object to
represent the error. Later in this chapter, we will deal with the types of objects that it

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:25 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


14
creates; however, notice that, in this case, we have asked the CLR to catch System.
Exception objects. This is the parent class of all exception objects, and by using it
within our catch block, we are assured that any exception will be caught.
Once the CLR has created the object, it transfers program control to the code follow-
ing the end brace after the try block. It then searches through the catch blocks (in this
case, there’s only one, but there could be many for different types of exceptions) until it
finds one that has the appropriate type of the exception as its parameter. The code
within the catch block is then executed. Remember that without the try and catch
blocks, the CLR throws the exception object and then, because it was not handled, cre-
ates an error dialog box and aborts the program.
The output from the preceding example will be as follows:

We caught an error!
We will now get to the end of the code!

The program did not abort in this instance. Rather, it is allowed to continue since, in
effect, we have “handled” the error. However, regardless of whether you follow this
approach or allow the CLR to terminate the program, the line after the attempted
divide-by-zero will never execute.
We mentioned earlier that the stack will unwind if the method containing the error
does not handle the error. The following simple example demonstrates this using our
DivideByZero code:

using System;
public class StackTest
{
public static void Main ()
{
try
{
MethodA();
} catch (DivideByZeroException d) {
System.Console.WriteLine ("Catching the appropriate exception");
} catch (Exception e) {
System.Console.WriteLine ("Here we are in Main()");
} finally {
System.Console.WriteLine ("This code will always execute");
}
}
public static void MethodA()
{
// this method simply calls MethodB
MethodB();
}
public static void MethodB()
{
int x = 0;
int y = 12;
int z = y / x; // LINE WITH THE ERROR
System.Console.WriteLine ("We never get here");
}
}

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:25 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


15
Keep this StackTest class file in your sights while we look at several issues that it
introduces.

PART I
The first issue is that the actual code that causes the error (displayed in bold) is not
enclosed in a try block directly. Instead, it has been called by a method that was called
by a method that was enclosed in a try block. When the line shown in bold is executed,
the CLR looks for exception handling in MethodB(). Of course, none is found, so it un-
winds the call stack looking back at MethodA() for a catch block, and then to
Main() where it finds the catch.
The next thing that you might notice about this code is that there are two catch
blocks in Main(). You may want to have the anticipated error caught (System.
DivideByZeroException) and then provide a default catch for any unanticipated
errors. You can code as many catches as you like, as long as you follow these rules:

• Order your catch blocks by the specificity of the exception that is handled.
This means that if you know a System.DivideByZeroException could
happen, code it first. In our example, if the catch blocks were in the reverse
order, the System.Exception block would be executed and our specific
handling of the division by zero ignored. Only one catch block will execute,
and control then passes to the finally block, if one is coded.
• You can place a general catch at the end of the catch blocks as follows:
} catch
{ // write some very general code here }
In this case, no actual object is caught, but the general catch block allows
you to handle completely unanticipated type exceptions. The compiler will
enforce the rule that this block must be at the end of the catch blocks.
• You cannot catch the same type of exception twice. For example, there
cannot be two catch blocks that start with:
} catch (DivideByZeroException d) {
• You cannot catch an exception of a type derived from the class of an
object from a previous catch. For example, if there was a class
System.DivideIntegersByZeroException that was a subclass of
System.DivideByZeroException, you could not code a catch block
for the subclass after the parent class, since one derives from the other.

The finally Block


The C# programming language allows you to execute code after a try block regardless
of whether there was an exception thrown. You accomplish this by coding a finally
block. C# guarantees that this code will execute even if attempts to side-step the block
are coded (such as break, continue, return, or goto statements). This is a very use-
ful concept.
Sometimes, you will want to end a program if an exception occurs. Take the example
of trying to open a file that cannot be found. That may be the key that stops the execu-
tion of the program. By coding a finally block after the catch that handles the

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:25 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


16
exception, you have a chance to release any system resources that have been used, and
you can perform any necessary cleanup routines before exiting the program.
In our previous StackTest example, we have coded a finally block, so the pro-
gram produces the following output:
Catching the appropriate exception
This code will always execute

Even if the highlighted line were changed as follows (which would not cause the
exception to be thrown), the finally block will execute:
int z = y / 2;

In that case the output would be as follows:


We never get here
This code will always execute

You may find the finally block useful for avoiding duplicate code. Suppose many
exceptions could occur within a particular try block. You would need catch blocks
coded for each type of exception, and perhaps, as a final piece of code, a routine that
must be executed regardless of which exception happens. Without the finally block,
you would have to code the segment in each catch block. Fortunately, you don’t have
to do this—just code it once in the finally block.

Throwing Exceptions
As a final note to this discussion, there may be times when you decide it is necessary to
cause an exception that can then be put through the normal handling routines. You do
this by using the throw keyword.
In the following code example, we ask the user for an integer between 12 and 42. The
user normally accommodates us by providing a value in that range. But occasionally a
value less than 12 or greater than 42 escapes from the user’s fingers. We can deal with
this by throwing an exception object that will handle the error.
using System;
public class UserInputTest
{
public static void Main ()
{
try
{
int x;
Console.Write ("Enter an integer between 12 and 42 : ");
x = Int32.Parse (Console.ReadLine());
if (x > 42)
throw new GreaterThan42Exception(); //home-grown exception
else if (x < 12)
throw new LessThan12Exception(); // home-grown exception
} catch (GreaterThan42Exception g) {
Console.WriteLine ("You entered a value greater than 42");
} catch (LessThan12Exception l) {
Console.WriteLine ("You entered a value less than 12");
} catch (Exception e) {
Console.WriteLine (e.Message);

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:26 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


17
}
}

PART I
class GreaterThan42Exception : Exception
{
// put some specific code here
}
class LessThan12Exception : Exception
{
// put some specific code here
}
}

The highlighted lines will cause the exceptions GreaterThan42Exception() or


LessThan12Exception() to be thrown, and then execution control moves to the
catch blocks where the exception can be handled. Remember the goal of this type of
coding—you have separated the exception-handling logic from the business logic of the
program, thereby accomplishing the decoupling goal of OOP.

.NET Framework Class Library Exceptions


The folks that brought you the .NET languages have anticipated a number of common
exceptions and provided prebuilt classes for you to use in your programs. These exist in
the Base Class Library (or, as it is also known, the .NET Framework Class Library). We
will briefly look at the System.Exception class; for more information on the BCL
and exceptions see Appendix D.

EXAM TIP All exceptions inherit from System.Exception. If you want


to catch all the exceptions from a try block, catch System.Exception.

System.Exception The System.Exception class is the parent class of all


exceptions. All other exceptions, whether they are prebuilt or home-grown (your
own exception classes), should derive from System.Exception. It’s a good idea to
become familiar with the properties and methods of this class, since any classes built
will inherit these properties and methods. Here are some of the properties:

• Message retrieves a message that describes the exception.


• Source gets or sets the name of the object that caused the exception.
• StackTrace allows you to display the call stack at the time of the exception.
This way you can chase back through the method calls to determine the
sequence of execution.
• TargetSite retrieves the methods that threw the exception.
• InnerException gets the Exception instance that caused the current exception.

The best way to become familiar with these properties and to explore the methods
that are either inherited by System.Object or are new to System.Exception and
thereby are inherited by all other exceptions is to review the .NET Framework Class
Library documentation.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:26 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


18

Creating Your Own Exceptions


When you design your business logic, you will find certain error conditions that will reg-
ularly arise. Errors such as “Not enough money to withdraw”, “No such customer”, and
so on, can be handled very nicely using the same approach that we have been discussing
in this chapter. Create your own exception classes, and throw the exception object when
the error occurs.
There are a few things that you should do when you create your own exception class:
• Inherit from System.Exception. As you can see in the previous section, you
may want to create your exceptions under ApplicationException.
• Override the constructor of the base class. In particular, you may want to set the
error message properly. The base class has been constructed as a bare-bones
class—you will need to override its behavior.
• Name your class file with a descriptive error name. For example, if you are
creating an exception class to describe the error condition “No such customer”,
call your exception class NoSuchCustomerFoundException. You will be
following the good example set by the Microsoft engineers.
The following class file definition illustrates a simple exception class:
public class NoSuchCustomerFoundException : ApplicationException
{
public NoSuchCustomerFoundException (string Message)
: base (@"Customer Not Found. The customer you have requested
cannot be found in the database. Try again, please")
{
}
}

This is a very simple example, but it does give you an idea of what you need to do to
create your own exception class. The next step entails throwing this exception when a
customer is not found. Presumably, your logic will go out to the database, search for the
customer, and return with the result of the search. If the customer was not found, you
would code the following line:
throw new NoSuchCustomerFoundException ();

The catch block would deal with the logic that pertains to an invalid customer
request.

Event Handling
Event handling is the area of programming that has given procedural developers the big-
gest problem over the years—what is an event and how it is handled? The first item on our
agenda must be the definition of an event. The examples commonly used to describe
event handling are based on the concept of a cup object, and we have found that this type
of example, rather than a code-based example, makes the topic easier to comprehend.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:26 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


19
When we use the term event, we are referring to something that is an object consid-
ered important to communicate to the world. For example, imagine a coffee-travel-mug

PART I
object: the specific object we have is blue in color with a black lid. The object has two
methods, drink() and spill(); two parameters, noSpill (closes the lid) and level (indi-
cates how much coffee there is in the cup). This can be a very common, everyday travel
mug, or it can be a software object that emulates a travel mug—either way we can inter-
act with the mug object.
Here is our task: We want to make sure we can refill the mug object as soon as it is
empty, so we need to perform a loop asking “is it empty?” that reads the level parameter
every so many seconds. When the level indicates that the mug is empty, the mug should
be refilled. We could have produced a procedural software structure similar to this
pseudo-code.

do while (true)
{
if (mug.level <= 0)
{
refill(mug)
}
}

This type of looping structure was the mainstay of the procedural world; we used to
draw lovely flowcharts so we would know the flow of execution through the applica-
tion. This type of processing is synchronous, with everything happening in a predeter-
mined order, and only in that order. In our travel mug example, the end result of all that
checking would be that coffee most likely would be removed from the daily food list—it
is too much work for the person checking the level in the mug.
The natural question is whether there is a better way, and fortunately there is. The
event model gives us the ability to have two or more objects communicating with each
other asynchronously.
We will bestow our travel mug with two events. For now we will just define an event as
something that is important to the object, and in this case we will create the empty
event and the full event. The mug will cause the empty event when the mug is empty
and the full event when the mug is close to overflowing. To take advantage of this new
better travel-mug model, we need to do one extra thing—we need to tell the mug that we
would like to be told when these events take place. This request is a registration of inter-
est. We give the mug a sticky note that says “Tell me when the empty event happens” and
gives an address where we can be contacted. Now we can go about our day doing what
we do best, and when the mug is empty we will get a message from the mug telling us
that it is empty.
This process is performed in the .NET environment every time we use an event.
Actually this is the processing that took place in previous versions of the Windows oper-
ating system, as well. In the software world, we call the event routing a callback. The
receiver of the event registers an address that should be called when the event fires (hap-
pens). The code that is called when the event fires is called the event handler.
Now let’s have a look at how we perform event handling in the .NET environment:
we use a delegate to connect the event with the code that will handle the event.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:26 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


20
Delegates
Previous languages in the C family use the concept of the function pointer; every function
occupies a block of memory, and the starting address is the function pointer. Being able
to refer to a function by its memory address (pointer) is very powerful, but it is also
fraught with dangers: if a pointer changes, the call to the location of the pointer will
most likely run code that will crash the application, or even the operating system. The
design of the C# language intentionally removed the ability to use pointers and perform
pointer operations that C and C++ permitted and that led to many difficult-to-locate
bugs. Instead, the C# designers created the equivalent of the function pointer in a
type-safe OO way: they created the delegate.
Here’s the one-sentence definition of a delegate: The delegate object encapsulates a
reference to a method.
Let’s look at how you declare and instantiate a delegate. The first step is to declare
the delegate, defining the return data type as well as the parameters. The following
code defines a couple of delegates:

// declare a delegate for a method that takes a single


// parameter of type string and has a void return type
delegate void MyDelegate1(string s);

// declare a delegate for a method that takes three parameters


// of type double, double, int and returns an int.
delegate int MyDelegate2(double d, double d1, int i);

Once the delegate is declared, we can instantiate it, as in the following code segment:

// Instantiate the delegate with a static method


// MyClass.Method1 must have this signature for the delegate to work:
// public static void Method1(string s)
MyDelegate1 k = new MyDelegate1(MyClass.Method1);

// Instantiate a delegate with an instance method


// The signature of the method must be:
// public int Method2(double d, double d, int i);
MyClass m = new MyClass();
MyDelegate2 p = new MyDelegate2(m.Method2);

When we have the delegate declared and instantiated, we need to call it. The follow-
ing code segment shows how to call a delegate.

// call Method1 through the delegate


k("Hello Delegate World");

// call Method2 through the delegate


int a = p(3.14159, 12.0003, 42);

Let’s have a look at a more complete example. Let’s build a console application that
will print assorted things for us and then call these methods through delegates.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:26 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


21
using System;
namespace Deleg

PART I
{
class Class1
{
delegate void MyprtString(string s);
delegate int MyprtNumbers(double d, double d1, int i);

static void Main(string[] args)


{
MyprtString a = new MyprtString(MyClass.prtString);
MyClass m = new MyClass();

MyprtNumbers o = new MyprtNumbers(m.prtNumbers);

Console.WriteLine(o(3.14159, 12.003, 42));


a("Jones");
}
}
class MyClass
{
public static void prtString(string s)
{
Console.WriteLine("Hello " + s +"!");
}
public int prtNumbers(double d, double d1, int i)
{
double x;
x = d * d1;
return (x < 12 ? 42 : i);
}
}
}

The two delegates, MyprtString and MyprtNumbers, are declared and instantiated
to encapsulate references (pointers) to the two methods in MyClass. When we execute
the program, it results in the following output:

42
Hello Jones!

In the examples we have worked with thus far, the delegate performed a single cou-
pling between the caller and the method. Such a delegate is known as a single delegate.
What would happen if the invocation of the delegate resulted in multiple methods
being called? There are several things that would need to be considered. For example,
the delegate would need to keep a list of all the methods that need to be called, and
some mechanism to add and remove methods from the delegates list would also be
needed. A delegate with multiple methods listed is called a multicast delegate.
Multicast delegates are derived from the System.MulticastDelegate class. All the dele-
gates have an invocation list with all the references that are to be called when the delegate
is invoked. The MulticastDelegate class has two static methods that are used to add
and remove references from the invocation list: the Combine and Remove methods. The

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:26 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


22
Combine method returns a delegate object with an invocation list that is the concate-
nation of the two delegate objects that were combined. The Remove method returns a
delegate object with an invocation list that is the original minus the reference to be
removed. The C# compiler will base all delegates that have a void return type on the
MulticastDelegate class.
The following example simplifies the concept of delegates, and in particular multicast
delegates. We will build some multicast delegates and exercise them.

using System;
namespace MultiDelegate
{
public delegate void PetDelegate();
class Application
{
static void Main(string[] args)
{
// instantiate the pet objects
Dog dog = new Dog();
Snake snake = new Snake();

PetDelegate a, b, c, d;

// assign the delegates


a = new PetDelegate(dog.Bark);
b = new PetDelegate(snake.Hiss);

// combine a and b as c
c = (PetDelegate)Delegate.Combine(a, b);

// invoke c(), the result should be that the two methods are called
c();

Console.Write("\n\n");
// combine c and a into d
d = (PetDelegate)Delegate.Combine(c, a);

// invoke d(), the result should be that three methods are invoked
d();
}
}
public class Dog
{
public void Bark()
{
Console.WriteLine("WOOF");
}
}
public class Snake
{
public void Hiss()
{
Console.WriteLine("Sssssssssssssss");
}
}
}

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:26 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


23
The output from this example follows, and you can see that there are two groups of
invocations (c() and d()). When we call c() we get two lines of output, but when we call

PART I
d() we get three lines.

WOOF
Sssssssssssssss

WOOF
Sssssssssssssss
WOOF

Microsoft has overloaded some operators in the C# language to make working with
delegates easier. We can use the plus sign (+) or the += operator rather than using the
Combine() method directly. Similarly, the minus sign (-) and the -= has been over-
loaded to give us the Remove() functionality. Using this syntax, we can rewrite the previ-
ous example as in the following code segment.

// combine a and b into c


c = a + b;

// combine c and a into d
d = c + a;

// remove a from c
c = c - a;

// or we can use the += and -= operators


c += a;
c += b'

d += c;
d -= a;

Events
Now that we’ve defined the delegates, we can look at how we declare, connect to, and
raise events. This is what we have learned so far:

• We have a class that will raise an event.


• We have code in a second class that will respond to the event by running the
code of the handler.

We now need a technique for connecting the event with the handler so we don’t have to
continually keep checking for the event. That connection is the delegate described in the
previous section.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:26 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


24
The first step in event processing is to declare the event and the delegate that will be
used to register clients to the event. The following code segment shows how that is done.

// declare the delegate for the event


public delegate void TravelMugEmptyEventHandler();

public class Mug


{
// declare the TravelMugEmpty event
public static event TravelMugEmptyEventHandler TravelMugEmpty;
// …
}

When we declare a delegate for a method with a void return type, the delegate will be
compiled as a MulticastDelegate by the C# compiler, and Combine and Remove meth-
ods are added for members from the invocation list. The client accesses those methods
with the overloaded operators += and -=.
The client code contains the method to handle the event, as well as the code to con-
nect the method to the event. The client code to use the TravelMugEmpty event will look
like this:

// The client's event-handling method


private void FillMug()
{
mug.Refill();
}

// initialization code to connect to the event handler


Mug.TravelMugEmpty += new TravelMugEmptyEventHandler(FillMug);

Once the object that has declared the event is ready to raise (or fire) the event, it
can use the event both as a class attribute and as a method. In our example, the
TravelMugEmpty event can be tested to see if it is not null—the event attribute will
be null only if there are no registered event handlers. If there are registered event han-
dlers, we raise the event by calling the event method TravelMugEmpty(), as can be
seen in this code segment:

// raise the TravelMugEmpty event if there are any connected event handlers
if (TravelMugEmpty != null) TravelMugEmpty();

Let’s recap the event handling:

• The class that is defining the event will declare the delegate and the event.
• The client will define the event-handling method and connect to the event.
• The class that defined the event tests to see if there are any clients registered,
and raises the event as needed.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:26 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


25

Summary

PART I
In this chapter, we have looked at how to work with character strings in the form of
System.String classes as well as System.Text.StringBuilder classes, and we
looked at where each can be used. We also discussed arrays and the utility methods
available for manipulating array data. We also looked at collections. There are a large
number of collections that can be built using the collection support in C#—there is a
special operator (foreach) that simplifies the way you can go through a collection from
the start to the end very efficiently.
We also looked at the techniques of error handling. Creating applications that handle
error conditions successfully is not rocket science. You simply need to understand when
the exception might occur and code your catch blocks accordingly. You will also have
to consider what kind of user-application errors could occur, and then build your cus-
tom exception class library.
Finally we discussed delegates and events, and how to declare them.
The next chapter will introduce the graphical environment that can be used when
working with C# in Visual Studio .NET.

Test Questions
1. Given the following code segment, what is the content of the string s in line 4?
1 string s = "Hello";
2 string r;
3 r = s;
4 r += " World!";
A. “Hello World!”
B. “Hello”
C. Nothing, it is garbage collected
D. The code will not compile
2. Which of the following array declarations will produce a compiler error?
A. int[] Integers = new int[] (1,2,3,4,5,6,7,8,9,0};
B. int[] Integers = new int[42];
C. int[] Integers = {1,2,3,4,5,6,7,8,9,0};
D. int I = 4;
int[] Integers = new int[I] {1,2,3,4};

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:27 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


26
3. In the following code, what will be printed by the Console.WriteLine()
method?
string[] str = {"Hello", "!", "World"};
Array.Reverse(str);
Console.WriteLine(str[0]);
A. “!”
B. “Hello”
C. “olleH”
D. “World”
4. In the following code, what will be printed by the Console.WriteLine()
method?
string[] str = {"Hello", "!", "World"};
Array.Sort(str);
Console.WriteLine(str[0]);
A. “!”
B. “Hello”
C. “olleH”
D. “Hello World !”
5. What is the outcome of the following code?
01 public void MethodB ()
02 {
03 int [] MyInts = new int [2];
04 try
05 {
06 for ( int i = 0; i < 3; i++)
07 {
08 MyInts[i] = i;
09 }
10 } catch (System.Exception e)
11 {
12 System.Console.WriteLine ("Some error occurred");
13 }
14 }
A. The code will not compile because there is an incorrect catch block.
B. The code will not compile because of an error on line 6.
C. The code will compile and displays “Some error occurred”.
D. The code will compile and will abort upon execution.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:27 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


27
6. What is the outcome of the following code?

PART I
01 public void MethodB ()
02 {
03 int [] MyInts = new int [2];
04 try
05 {
06 for ( int i = 0; i < 3; i++)
07 {
08 MyInts[i] = i;
09 }
10 } finally
11 {
12 System.Console.WriteLine ("This is executed");
13 }
14 }
A. The code will not compile because there is a missing catch block.
B. The code will compile and abort upon execution.
C. The code will compile and displays “This is executed”.
D. The code will compile and will abort upon execution and then display
“This is executed”.
7. You need to define a delegate for the following method:
public class Class1
{
public static int Method42(int i)
{
return i*42;
}
}
How is the delegate for Method42() declared?
A. delegate Class1.Method42;
B. delegate int Met42(int i);
C. delegate void Method42(string s);
D. delegate int Class1.Method42(int i);
8. What kind of delegate will be created for the following method?
public void Method12(object sender, System.EventArgs e)
{

}
A. Single delegate
B. Event delegate
C. Multicast delegate
D. Proxy delegate

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:27 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide


28
9. The following code segment creates an event handler. What text must be
inserted in place of <<replace text here>> for the event to work?
// declare the delegate for the event
public delegate void SendFaxEventHandler();

public class Fax


{
// declare the SendFax event
public <<replace text here>> event SendFaxHandler SendFax;
// …
}
A. void
B. delegate
C. Combine
D. static
10. You are building an event handler for the SendFax event from the sFax
component, and you have written the following code. When you test the
event handler, you find that it never runs. What code must you add to your
application to make the event execute in response to the SendFax event?
private void Send_Fax()
{
Console.WriteLine("Fax is sent!");
}
A. public delegate SendFax(Send_Fax);
B. this.sFax.SendFax += new SendFaxHandler(this.Send_Fax);
C. public event SendFax(Send_Fax);
D. this.sFax.SendFax =+ new SendFaxHandler(this.Send_Fax);

Test Answers
1. B. Through all the processing the content of s never changes.
2. D. The array constructor cannot take an explicit size parameter as well
as initialization.
3. D. The output is the first string in the array, the array was reversed so the
output is “World”.
4. A. The output is the first string in the array, the array was sorted so the output
is “!”.
5. C. The array has size 2, we try to access index 0, 1, and 2. There will be an
exception when we try to access index 2, resulting in an exception, the catch
block will sink the exception, then the finally block will execute.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:27 PM
Color profile: Generic CMYK printer profile
Composite DefaultAll-In-One
screen / MCAD/MCSD Visual C# .NET Certification All-in-One Exam Guide / Rempel & Lind / 222443-6 / Chapter 4

Chapter 4: Strings, Exceptions, and Events


29
6. D. The array has size 2, we try to access index 0, 1, and 2. There will be an
exception when we try to access index 2, resulting in an exception, then the

PART I
finally block will execute.
7. B. The delegate should have the same signature as the method it will
encapsulate, except the name must be unique in the scope.
8. C. Any delegate that is declared as public void is a multicast delegate.
9. D. Events must be declared as static.
10. B. The delegate must be registered, the += operator performs that action.

P:\010Comp\All-in-1\443-6\ch04.vp
Friday, August 23, 2002 4:57:27 PM

You might also like