Exception Handling Redux

I l @ ve RuBoard

Mistakes happen. Errors are fact of life. That error handling in applications is important is beyond obvious, but Visual Basic developers have had their own set of challenges. The error handling mechanisms of the past are not really suited to larger-scale applications. Visual Basic .NET supports the classic On Error syntax, but it also introduces structured exception handling.

Note

On this subject, we are very biased . Structured exception handling is far more flexible and useful than the "old way." If you're developing a new Visual Basic .NET application, treat any use of On Error statement as a bug. I know that many Visual Basic developers like to use what they're most comfortable with, but On Error is like a clumsy sledge hammer and really should be avoided at all costs. Chapter 11 discusses the performance problems associated with On Error .


Exception Handling Basics

Exception handling is based on a throw-catch metaphor. When an exception is generated by a block of code, we say that it " threw " an exception. If we define an exception handler for that exception type, we say that we "caught" that exception. Visual Basic .NET uses the Try Catch Finally block to define exceptions handlers. A simple example looks like the following:

 PublicSubTest() Try 'Dosomeworkthatmightcauseanexception CatchexAsException MsgBox(ex.ToString()) EndTry EndSub 

Of course, you can get more sophisticated in how you handle exceptions. It is important to note that exceptions are just another type of class that all inherits from the base class System.Exception . Therefore, you can use the Catch statement as an exception filter and specify only the exceptions that you are able to handle:

 PublicSubTest() Try 'Dosomeworkthatmightcauseanexception CatchexAsFileNotFoundException MsgBox("Couldnotfindthefile: " +ex.FileName) CatchexAsSecurityException MsgBox("Youdonothavepermissionstoaccessthisobject") EndTry EndSub 

Here you can see how it is possible to catch two different types of exceptions and provide custom error handling. Note that if any other exception type is produced in our Try block, the exception will not be caught in this code. This is on purpose, and it is how you should approach exception handling in your own code. Generally speaking, you should never catch an exception unless you intend to do something with it. End of story.

The last part of this particular discussion of the Try Catch block has to do with the Finally clause. The Finally code block contains code that is guaranteed to be executed, no matter what. This allows you to insert cleanup code that will always run.

 DimconnAsNewSqlConnection("Aconnectionstring") DimcmdAsNewSqlCommand("Select*fromAuthors",conn) Try conn.Open() cmd.ExecuteReader() CatchexAsSqlException MsgBox(ex.ToString()) Finally 'Thisalwaysgetscalled,whetheranexceptionhappensornot If(NotconnIsNothing)AndAlso_ (conn.State=ConnectionState.Open)Then conn.Close() EndIf EndTry 

Alternatively, you can forgo the catch statement altogether and just include the Finally block:

 DimconnAsNewSqlConnection("Aconnectionstring") DimcmdAsNewSqlCommand("Select*fromAuthors",conn) Try conn.Open() cmd.ExecuteReader() Finally 'Thisalwaysgetscalled,whetheranexceptionhappensornot If(NotconnIsNothing)AndAlso_ (conn.State=ConnectionState.Open)Then conn.Close() EndIf EndTry 

This is a way of saying that you can't handle the exceptions that might be generated by the code in the Try block, but you should always close the connection, regardless. Pretty cool, huh?

Throwing Exceptions

Throwing exceptions yourself is not exactly difficult. The .NET Framework makes it that much easier by defining a whole set of exception classes that you can use:

 PublicSubErrorSub() 'Dostuff ThrownewException("ErrorSubfailedbecauseyoumadeamistake!") EndSub 

Don't use the System.Exception class if a more appropriate exception handling type is available to you. If your code is failing because a necessary file does not exist, use an instance of the FileNotFoundException class ”it has additional properties that can be useful for debugging purposes.

An interesting property of .NET exceptions is that they can contain other exceptions. The System.Exception class defines a property called InnerException of type System.Exception . This property allows you to access an exception that is contained by another. It also potentially allows the development of an exception hierarchy. This allows you to provide better information about what failed and still provide a way to track down the original error. The following code demonstrates how you might use the exception containment mechanism. Using an overload of the System.Exception class constructor, we'll create a new exception, passing the previously caught exception:

 PublicSubErrorSub() 'Dostuff Try 'Dostuffthatmightfail. CatchexAsSqlException ThrownewException("ErrorSubfailedbecauseyoumadeamistake!",ex) EndTry EndSub 

That's pretty much all there is to throwing. The newly thrown exception will have an InnerException that contains the SqlException caught by our Catch statement.

Now that we've covered the basics of throwing and catching exceptions, it seems appropriate to take a step back and look at exception handling practices you should avoid.

Exception Handling No-Nos

Structured exception handling is no panacea. There are a couple of rules you should follow to maximize the benefits and efficiency of exception handling:

  • Never catch an exception unless you intend to do something with it.

  • Never catch an exception if you're just going to rethrow it.

  • Catch the most specific exception you can.

  • Create multiple catch statements for specific exception types if you'll handle them.

It's not unheard of for developers to get exception-handler-happy. When that happens, we see code like this:

 PublicSubTest() Try 'Dosomeworkthatmightcauseanexception CatchexAsException Throwex'Don'tdothis!! EndTry Try 'Dosomemoreworkthatmightcauseanexception CatchexAsException IfTypeOfexIsFileNotFoundExceptionThen 'Dosomethingtorecover Else Throwex'Don'tdothis!! EndIf EndTry EndSub 

In the first Try block, the exception is caught and immediately rethrown ”a bad idea and a waste of resources. If you can't handle the exception, don't catch it. It's that simple. The second Try block does something similarly foolish. It catches all possible exceptions and checks the type to see if it is a FileNotFoundException to handle the error. If the caught exception is not a FileNotFoundException , the method just rethrows the caught exception. This also is very inefficient and unnecessary. You can get the same result by being more specific in your Catch statement. Always remember the first rule of exception handling: if you don't do anything with it, don't catch it. Fixing the previous example results in code like the following:

 PublicSubTest() 'Dosomeworkthatmightcauseanexception Try 'Dosomemoreworkthatmightcauseanexception CatchexAsFileNotFoundException 'Dosomethingtorecover EndTry EndSub 

Remember, exceptions are fairly expensive, so as a general rule exceptions should be truly exceptional ”avoid overusing them. In many cases, the old standby of returning a success value is perfectly acceptable. On the other hand, if something unexpected happens, the function should throw an appropriate exception. The rule here is based on how often you expect the event to occur. Throw an exception if an error condition is truly exceptional (such as when an expected user record does not exist). If the error happens routinely (for example, an incorrect password), programmatically checking for errors is a much more efficient and appropriate approach.

Custom Exceptions

The .NET Framework defines a wide variety of exceptions types. But sometimes the right kind of exception just isn't available, or you face a whole class of problems that have nothing to do with file or SQL exceptions and are related to specific features in your application. In such cases, you'll probably want to create your own set of exceptions. If you decide to do this, it's best to plan out a hierarchy in advance.

All exceptions in Visual Basic .NET inherit from the System.Exception class. The .NET Framework further defines exceptions into two main categories: the System.ApplicationException class and the System.SystemException . The System.ApplicationException class is intended to be the base exception class for all application-specific exceptions you define. Most exceptions defined by .NET Framework derive from System.SystemException .

As much as possible, you should use the existing exceptions defined by the .NET Framework. You should define new exceptions only if the existing exceptions don't suffice. When you define a new exception, create your own base exception that's derived from the System.ApplicationException class. You can then build your application's exception hierarchy off of this base class. The following example demonstrates creating a base exception class called MyAppException that's derived from System.ApplicationException . It also shows how to create a specific exception type ( UserConfigException ) from MyAppException that provides additional information about the error that occurred.

 PublicClassMyAppException InheritsSystem.ApplicationException PublicSubNew() MyBase.New() EndSub PublicSubNew(ByValmessageAsString) MyBase.New(message) EndSub PublicSubNew(ByValmessageAsString,_ ByValinnerExceptionAsException) MyBase.New(message,innerException) EndSub EndClass PublicClassUserConfigException InheritsMyAppException Privatem_fileNameAsString PublicSubNew(ByValmessageAsString,ByValfileNameAsString) MyBase.New(message) m_fileName=fileName EndSub PublicReadOnlyPropertyFileName()AsString Get Returnm_fileName EndGet EndProperty EndClass 

You'll see many examples of exception handling throughout this book. If you need more information, see the MSDN documentation that comes with Visual Basic .NET.

I l @ ve RuBoard


Designing Enterprise Applications with Microsoft Visual Basic .NET
Designing Enterprise Applications with Microsoft Visual Basic .NET (Pro-Developer)
ISBN: 073561721X
EAN: 2147483647
Year: 2002
Pages: 103

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net