Read Microsoft Visual C# 2005 Express Edition: Build a Program Now! Online
Authors: Patrice Pelland
Tags: #General, #Computers, #C♯ (Computer program language), #Programming Languages, #C#, #Microsoft .NET Framework, #Computer Books: Languages, #Computer Graphics, #Application software, #C# (Computer program language), #Programming, #Microsoft Visual C# .NET, #Microsoft Visual C♯ .NET, #Electronic books, #Game Programming & Design, #Computing: Professional & Programming, #C (Computer program language), #Computers - Languages, #Programming Languages - C#, #Programming & scripting languages: general
keywords.
source code of the ReadFile method.
The ReadToEnd method reads the content of the opened file and puts it in a string variable. Press 5
Shift+F11
and then
F11
. A message box should display the string variable content. Click
OK
in the message box. You should now be back at the caller.
Step into the code until you get the string Helloworld in a message box. Pay attention to the order of 6 execution and look into the variables and into the content in each of the tab sections. 7 Step into the code again to get into the ManipulateStrings method.
Chapter 7: Fixing the Broken Blocks
119
C07622299.indd 119
C07622299.indd 119
10/24/05 7:13:57 PM
10/24/05 7:13:57 PM
The first instruction in the ManipulateStrings method is taking the string received in argument and converting it to an array of characters. The reason this is done is because strings are immutable in .NET, and therefore you have to work with them in read-only mode once they’re created. Methods modifying a string are actually returning a new string object that contains the modification applied to it.
As you can see in the source code, one of the ManipulateStrings arguments,
myString, is passed with the ref keyword. When you have an argument that
is passed to a method by reference, the called method is receiving a refer-
ence to the same memory location used by the caller. Therefore, if the meth-
od is modifying the content of that argument, it is modifying the content at
this memory location and thus modifying the variable from the caller. In this
case, anything that is done to the myString argument will modify the value
of the variable in the calling code. The other argument is myPosition, and it
is passed by value. When you have an argument that is passed by value, the
method is receiving a copy of the variable from the calling code and thus
can’t modify the original value from the caller. Therefore, the content will
get lost when the method ends and execution flow returns to the caller.
Therefore if you want to modify a string character by character or if you want to access one single character in a string by using an index, you first need to convert the string into an array of characters.
TO BEGIN STEPPING OUT OF THE MANIPULATESTRINGS METHOD
1 Press
Shift+F11
to step out of the ManipulateStrings method, or you can press the
Step Out
button. The application stops abruptly. What just happened is an unhandled exception. An unhandled exception happens whenever an error occurs that is not anticipated or handled explicitly by your application. In that case, the execution of your application is halted because there is no way the application can continue in that state without potentially corrupting the memory or opening security holes. One of the .NET runtime (CLR) principles is to make sure that neither ever happens. Therefore, the CLR crashes your application to prevent your application from continuing to execute in an unknown state. Even though the CLR is taking those precautions, it is less probable to have insecure code executing in .NET, but still possible.
To help you find the bug that raised that unhandled exception, Visual Studio includes
120
Microsoft Visual C# 2005 Express Edition: Build a Program Now!
C07622299.indd 120
C07622299.indd 120
10/24/05 7:13:58 PM
10/24/05 7:13:58 PM
another useful tool: the
Exception Assistant
. This assistant replaces the previous Exception dialog box, and it’s helpful because, based on the context of the exception, it provides more information than before, such as: the type of exception, troubleshooting tips, and corrective actions that may be applied through the Exception Assistant. Look at Figure 7-8 to see what it looks like for the current exception.
When you look at the exception name, the troubleshooting tips, and the data visualizers, it can become apparent why an unhandled exception was raised. The exception name alone is self-explanatory: IndexOutOfRangeException. The first troubleshooting tip displayed asks you to make sure the maximum index on a list
is less than the list size. Arrays in .NET are 0
based; this means that the first element starts
at index 0. The length of the string received as
argument is 10, as shown in Figure 7-8.
The intent of this method was to modify the
last character of the string when the position in
the array is equal to a position passed by value
to the method. In this particular case, the position passed by value to the method is 1. Therefore, in the “for loop” at the second
character of that string, the “if” statement will
return true and then the index
i
will get the
value of the string length. This means that
i
is
now equal to 10. When the application tries to
Figure 7-8
modify the character at index 10, an exception will be generated because index 10 is outside
Exception assistant
of the range of the array. The array has 10 characters with index from 0 to 9. Figure 7-9 uses a new visualizer to look at the char array content.
Figure 7-9
When you move the mouse over program elements,
Array visualizer
you’ll sometimes see a magnifier. If you click the dropdown list, you will see a list of visualizers that display the information in a way that is meaningful to the data
type you’re looking at. For instance, if you’re working
with Extensible Markup Language (XML) or Hypertext
Markup Language (HTML) content, the XML or HTML
Chapter 7: Fixing the Broken Blocks
121
C07622299.indd 121
C07622299.indd 121
10/24/05 7:13:59 PM
10/24/05 7:13:59 PM
visualizer will allow you to see the content as if you were using Microsoft Internet Explorer or any other XML/HTML tool. You’ll use one of the visualizers soon when you debug the ReadFile method.
TO FIX THE OUT OF RANGE PROBLEM
Modify the ManipulateStrings method. Subtract 1 from the string length when you assign a new value 1 to i. The source code should look like this after you modify it:
if (i == myPosition)
If at any time you use the Edit and
Continue feature and you see that
{
your data is odd-looking or seems
i = myString.Length - 1;
corrupted, stop the debugging
myTempCharArray[i] = ‘Z’;
process and restart it.
}
After modifying this line of code, move your next execution pointer to the “for” statement so that 2 index i starts at 0. Step through the code or step out. This time there should be no exception. Continue to step through the code; you should now see another message: HelloworlZ. The string has been modified because it was passed by reference.
Continue to step through the code and soon you’ll get a second exception, which is a Division by 0 error. Of course, an exception is raised because the Divide method assigns 0 to the denominator when the numerator is greater than 5. Using a visualizer, you can see that the numerator is 6, therefore 0 will be assigned to the denominator.
Again, the first displayed troubleshooting tip helps by suggesting that you make sure the denominator is not 0. To solve the problem, you could add an “if” statement; but before you do that, consider another .NET principle.
A good practice in .NET is to use the exception mechanism to catch those corner cases instead of coding special conditional instructions which bloat the code. The exceptions are an integral part of the .NET framework and they’re everywhere. Let’s see the logic behind this decision.
122
Microsoft Visual C# 2005 Express Edition: Build a Program Now!
C07622299.indd 122
C07622299.indd 122
10/24/05 7:14:00 PM
10/24/05 7:14:00 PM
In a real application, your application would not purposely assign 0 to the denominator; therefore, most divisions would result in a correct operation. Adding an “If” statement would result in a conditional instruction executed for every single division. And because most divisions would be valid, you would automatically slow down your application. Using an exception-handling mechanism to catch those corner cases is a much better solution because the exception-handling code will get executed only when necessary, so your application should be faster.
When you insert exception-handling code in your application, it is best practice to always catch exceptions from the most precise to the least precise. In this case, you know that the DivisionByZeroException is the one most likely to occur; therefore, it's the first one you want to catch.
When you catch an exception, the exception is “handled.” You then need to do something about it; either you handle it by mentioning it to the user or you throw the exception back. In this case, you want the user to know that an exception was raised but you don’t want the program to crash. Here's an example that demonstrates this form of handling that I'm sure you already know. If you try to divide by zero in Microsoft Office Excel®, Excel won’t crash; it will simply indicate that your entry results in a division by zero and display the
#DIV/0! message in the cell.
An older way of doing things was to make your method return an integer to indicate success or failure. And that’s where people met with trouble because between two applications, and sometimes between two functions, the same integer code meant two different things. You received an integer that was supposed to tell you why your application failed, but the originating code had two meanings, and it was a nightmare to figure out which one was the valid error code. In addition, when people used error codes, their code was ugly because they either had a switch case or a series of nested ifs.
In .NET, you should never design your methods to return an integer to indicate success or failure, nor should you use a Boolean for the same purpose. This is a bad practice that was used when exceptions did not exist or when people didn't know or want to use them appropriately.
You should never do this.
Instead, use exceptions.
Chapter 7: Fixing the Broken Blocks
123
C07622299.indd 123
C07622299.indd 123
10/24/05 7:14:00 PM
10/24/05 7:14:00 PM
TO ADD CODE TO HANDLE DIFFERENT EXCEPTIONS
Click the Stop Debugging button or press Shift+F5 to stop debugging mode. In TestApplication.cs, 1 modify the button1_Click method to look like the following:
Library myObjectLibrary = new Library();
string myString = “Helloworld”;
string myFile = “”;
try
{
MessageBox.Show(myObjectLibrary.Divide(5, 3).ToString());
MessageBox.Show(myObjectLibrary.Divide(3, 3).ToString());
MessageBox.Show(myObjectLibrary.Divide(6, 4).ToString());
}
catch (DivideByZeroException ex)
{
MessageBox.Show(ex.ToString());
}
try
{
myFile = “MyExistingTextFile.txt”;
MessageBox.Show(myObjectLibrary.ReadFile(myFile));
myFile = “MyNotExistingTextFile.txt”;
MessageBox.Show(myObjectLibrary.ReadFile(myFile));
}
catch (FileNotFoundException)
{
MessageBox.Show(myFile + “ doesn’t exist!”);
}
myObjectLibrary.ManipulateStrings(ref myString, 20);
MessageBox.Show(myString);
myObjectLibrary.ManipulateStrings(ref myString, 1);
MessageBox.Show(myString);
Remove all the breakpoints in TestApplication.cs and Library.cs and execute the code. Look at the dif2 ferent message boxes. If a DivideByZeroException or FileNotFoundException occurs, a message box will be displayed.
124
Microsoft Visual C# 2005 Express Edition: Build a Program Now!