Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / Windows Forms

Using Try... Catch..., Finally!

Rate me:
Please Sign up or sign in to vote.
4.80/5 (45 votes)
5 Feb 2011CPOL18 min read 321.4K   2.4K   101   30
This article describes multiple implementations of proper Try... Catch... Finally and Using... End Using blocks in your code.

Introduction

Error handling is an important part of any software developers' job. The .NET Framework offers some very powerful tools to handle errors in a relatively easy manner.
One of these tools is the Try... Catch... Finally... statement. Yet in the few months that I have been programming, I have seen quite some (wrong) uses of the Try... Catch... Finally... not only by beginning progammers, but also by so-called seniors and gurus!
There are many books and articles discussing correct error handling in .NET, but many fail to give a simple yet complete overview of the so-important Try... Catch... Finally... block.
With this article, I hope to inform any software developer about some proper and detailed uses of the Try... Catch... Finally... block.

Using the Example Project

For this article, I have made a small example application dealing with various uses of the Try... Catch... Finally... statement. The example is easy to use and debug.
The example consists of a single form with some buttons on it. Each button demonstrates a specific use of the Try... Catch... Finally... block and should be debugged using breakpoints to fully understand. Note that the code itself does not actually do anything. It simply throws exceptions and handles them.

The project was made using Visual Studio 2010 Express Version using .NET Framework 4.0. However, all of the code could easily be used in any .NET 3.5 application as well.

UsingTryCatchFinally.jpg

Some Basics about Exceptions 

No matter how well you test an application, eventually an error will always occur. Perhaps a connection to a database fails, or you are trying to open a file which does not exists on the users' computer or to which the user has no access. If such an error occurs, the .NET Framework gathers information about what just went wrong and stores this in an Exception object which is then thrown up (or down?) the stack. The .NET Framework knows numerous types of Exceptions, such as the FileNotFoundException, IndexOutOfRangeException and the SqlException. Some of these Exception classes provide specific information about what just happened. For example, the SqlException contains information about the severity of the SqlError.

No matter what kind of Exception is thrown, they all inherit from the System.Exception class. When an Exception is thrown by the .NET Framework, it automatically looks for the first Catch block (contained in a Try... Catch... block) in the stack. If the stack does not contain any Catches, an Unhandled Exception occurred. This will give your end-user a prompt saying that an Unhandled Exception occurred and that they can continue and ignore the error or quit the application. What happens next is a mystery. In the best case, your application is closed either way. In the worst case... Let's just not think about that. :)
As a developer, you generally do not want users to see such a message. Therefore, it is important to always implement error handling in your code by using Try... Catch... blocks.

Starting the Sample Project

When you open the example project, you will see a form with numerous buttons.
I know the big red button looks tempting, but let's not press it right away. Instead, first build the project. Now go to your debug folder (usually located in your solution folder) and run the executable. Now you may press the big red button. That does not look very good, does it?
Now press any other of the buttons (except Close) and notice the difference. Go back to the project file again. Before running the application, I want you to press the shortcut keys Control + Alt + E in Visual Studio. This will display the Exception Dialog. Make sure both checkboxes behind 'Common Language Runtime Exceptions' are checked. This will make sure that you go into debug mode whenever an Exception is thrown in your code. It is recommended that you fully step through the code of any button by using Breakpoints and F8 to follow the paths that Exceptions make when dealing with Try... Catch... Finally blocks.

A Simple Try... Catch...

Open the project and press the first button on the form, simple Try... Catch.... You will immediately be sent to the source code. It is not a very exciting piece of code, but this is where it all starts. 

VB.NET
Private Sub btnSimpleTryCatch_Click(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles btnSimpleTryCatch.Click
        Try
            ' Some code here...
            ' Oops! An error occurs!
            Throw New System.Exception("An unexpected error occurred")
            ' Some more code here... This will not be executed if the Exception occurs.
        Catch ex As Exception
            ' Handle the exception.
            MessageBox.Show(ex.Message, Me.Text, _
		MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

Notice what happens. I am trying (Try...) to run some code, but for some reason, an Exception is thrown. Instead of crashing my application, the Exception looks for the first Catch it can find. Fortunately, a Catch happens to be nearby and the Exception can be handled. Be aware of the fact that any code between the Throw and the Catch is NOT executed. The Exception jumps over this code and goes straight to the Catch block. Also notice that I Catch ex as Exception. Remember that every type of Exception inherits from the Exception object? That means that this little bit of code is able to catch ANY Exception! In this case, I simply let the user know that something went wrong by using a MessageBox and showing the Message property of the Exception object. Now, whatever code is between the Try... Catch... and whatever might go wrong is automatically handled by showing a prompt to the user. Easy, no?

A Simple Try... Catch... Finally...

Let's move on to the second button on the form. Click it and notice that your cursor turns into a waiting cursor! Unfortunately after a few seconds, all goes wrong...

VB.NET
Private Sub btnSimpleTryCatchFinally_Click(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles btnSimpleTryCatchFinally.Click
        ' The cursor goes into waiting mode.
        Me.Cursor = Cursors.WaitCursor
        Try
            ' Some code here...
            ' This is some heavy code!
            Threading.Thread.Sleep(5000)
            ' Oops! An error occurs!
            Throw New System.Exception("An unexpected error occurred.")
            ' Some more code here...
        Catch ex As Exception
            ' Handle the exception.
            MessageBox.Show(ex.Message, Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            ' Make sure the cursor is set back to default!
            Me.Cursor = Cursors.Default
        End Try
    End Sub

This piece of code looks very much like that of the previous button, with the exception that this is a long process and we turn the cursor into a wait cursor. I have often waited a long time for applications that appeared to be loading, but had actually crashed which caused my cursor to always stay in waiting mode! So how do we make sure the cursor in OUR application always turns back to default? Easy, we use a Finally... block. The Finally... statement in a Try... Catch... Finally... block is ALWAYS executed. So if everything would go as it should, my code would be executed, it would skip the Catch block, go into my Finally block and put my cursor back to normal. If an Exception occurs (like here), the code jumps into the Catch block, handles the error and then goes into my Finally block, making sure that my cursor is turned back to normal. Notice how I initially change my cursor outside of the Try... Catch... Finally... block. This makes sure that when I go into my Finally, my cursor is actually a wait cursor. In this example, it would not matter if the first line of code is inside or outside the Try... Catch... Finally... block. But it will matter later on as you will see. I should also mention that the Try... Finally... block can also be used without the Catch. We will see an example of that later on.

Multiple Catches

In some cases, you might want to handle certain Exceptions differently than others. The following example provides an explanation of multiple Catches in a single Try... Catch... block. For the example, let's just say we are trying to open a file on the users' computer. Anything could happen. Maybe the directory of the file you are trying to open does not exist, maybe the file does not exist, maybe the user has no rights to open the file or maybe something completely unexpected occurs. In this case, you can use multiple catches, as the following code snippet shows: 

VB.NET
Private Sub btnMultipleCatches_Click(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles btnMultipleCatches.Click
        Try
            ' Some code here...
            ' Let's say we're trying to open a file here.
            ' Oops! An error occurs!
            Dim rand As New Random
            If rand.Next(2) = 1 Then
                Throw New IO.FileNotFoundException_
		("The file you are trying to open was not found.")
            Else
                Throw New System.Exception("An unknown error occurred.")
            End If
            ' Some more code here...
        Catch dirEx As IO.DirectoryNotFoundException
            ' Handle the specific DirectoryNotFoundException here.
            MessageBox.Show(dirEx.Message, "Directory not found", _
		MessageBoxButtons.OK, MessageBoxIcon.Error)
        Catch fileEx As IO.FileNotFoundException
            ' Handle the specific FileNotFoundException here.
            MessageBox.Show(fileEx.Message, "File not found", _
		MessageBoxButtons.OK, MessageBoxIcon.Error)
        Catch ioEx As IO.IOException
            ' Handle other non-specific IO Exceptions here.
            MessageBox.Show(ioEx.Message, "IO exception", _
		MessageBoxButtons.OK, MessageBoxIcon.Error)
        Catch ex As Exception
            ' Handle any other non-IO Exception here.
            MessageBox.Show(ex.Message, "Unknown exception", _
		MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

Note how an Exception is generated using the Random class. 50% of the time, we will get a FileNotFoundException and 50% of the time, we will get a non-specific Exception.
At this point, you might want to uncheck the checkbox you checked at the beginning of this article by using Control + Alt + E and press the 'Multiple catches' button a couple of times to see how it can show two different MessageBoxes (either the "File not found" or the "Unknown exception" MessageBoxes).

If the Exception is thrown, it will look at the first Catch block that it can use. In this case, for the FileNotFoundException this is the Catch fileEx As IO.FileNotFoundException. Notice that the FileNotFoundException skips the Catch dirEx As IO.DirectoryNotFoundException block, because it is no DirectoryNotFoundException. Also, if the fileEx has been handled in the fileEx block, it will not step into the ioEx or the ex block anymore.

Both the FileNotFoundException and the DirectoryNotFoundException inherit from the IOException. This means that if I had put the Catch ioEx As IO.IOException block above the other two Catch blocks, the FileNotFoundException and the DirectoryNotFoundException would never jump in their respective Catch blocks!
When handling Exceptions of multiple types, you must first specify the most specific Exception block. The general Catch ex as Exception should always be on the bottom of the hierarchy because every Exception can jump into this block, preventing them from jumping into more specific Catch blocks after that.

A Finally... block could still be added at the bottom of the Try... Catch... block.
If you have unchecked the 'Common Language Runtime Exception' checkbox by using Control + Alt + E, do not forget to turn it on again.

Exceptions from Deeper Methods

A common misconception about Try... Catch... is that every block of code should have one. This is not true in many (if not most) cases. To illustrate this, I have made a class named "ManyMethods" which exposes three Public members which step into a couple of methods. None (with the exception of one) of these methods contain a Try... Catch... block. Yet, the last method where all of these methods will end eventually always throws an Exception. If none of the methods has a Try... Catch... block, then where will this Exception be handled? Easy, in the first block of code on the stack that does have a Try... Catch... block. In this case, the event handler of the button.

VB.NET
Private Sub btnExceptionsFromDeeperMethods_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnExceptionsFromDeeperMethods.Click
    Try
        Dim mm As New ManyMethods
        ' This method goes into three other methods!
        mm.GoIntoDeeperMethods()
    Catch ex As Exception
        MessageBox.Show(ex.Message & Environment.NewLine & _
                        "The method which threw me was: " & ex.TargetSite.Name, _
                        Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
    End Try
End Sub

Public Sub GoIntoDeeperMethods()
    B() ' Goes into B, which goes into C, which goes into ExceptionMethod,
        ' which throws an error.
    MessageBox.Show("You will never see me!", "Some deeper method", _
    MessageBoxButtons.OK, MessageBoxIcon.Information)
    AA() ' Will never be executed.
    AB() ' Will never be executed.
End Sub

' Method B, C, AA and AB show MessageBoxes,
     ' but only after eventually calling the ExceptionMethod.
' The MessageBoxes will therefore never be prompted.

Private Sub ExceptionMethod()
    ' Some code here...
    ' Oops! An error occurs!
    Throw New System.Exception("I am coming from way down here!") ' This returns
    ' to the first Catch block, in the case in the button Event Handler.
    ' Some code here...
End Sub

So even though none of the methods that this piece of code jumps into has a Try... Catch... block, the Exception will simply come back here and let the user know something went wrong.
Also note that I use the 'TargetSite' property of the Exception object. This property contains the method which threw the Exception (see the System.Reflection.MethodBase http://msdn.microsoft.com/en-us/library/system.reflection.methodbase.aspx namespace for more information). I am using this property to prove that the Exception really was thrown a few methods in the calling method, but that if an Exception occurs, it can simply be handled in the first Try... Catch... block, no matter where in the stack it is.

Also check the other methods in the ManyMethods class. They are all called by the methods the code runs through. Yet, because an Exception occurs, the calling code will never execute.

Finally in Deeper Methods 

This example is almost the same as the previous one, with one difference. In this example, I put a method between my button Event Handler and the method that eventually calls the ExceptionMethod. This extra method contains a Try... Finally... block. So click the button and see what happens.

VB.NET
Private Sub btnFinallyInDeeperMethods_Click(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles btnFinallyInDeeperMethods.Click
        Try
            Dim mm As New ManyMethods
            ' This method goes into four other methods!
            mm.GoIntoDeeperMethodsWithFinally()
        Catch ex As Exception
            MessageBox.Show(ex.Message & Environment.NewLine & _
                            "The method which threw me was: " & ex.TargetSite.Name, _
                            Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

	Public Sub GoIntoDeeperMethodsWithFinally()
        Try
            ' This will eventually throw an exception.
            GoIntoDeeperMethods()
        Finally
            ' This code will ALWAYS be executed.
            MessageBox.Show("You will always see me!", _
		"Finally", MessageBoxButtons.OK, MessageBoxIcon.Information)
        End Try
    End Sub

As you can see, when you press the button and step through the code, the Finally... statement in this block of code will be executed, even though the Exception is not thrown or handled here. Any Finally... block between the throwing of an Exception and the handling of an Exception will always be executed. This is especially useful when you have to Dispose of objects or make changes to the user interface (such as transforming the cursor in the first Finally... example).

Handling an Exception Multiple Times

When an Exception is thrown from a Class that is called from a Form, it is possible that you want to do some Exception Handling in the throwing Class before you handle the Exception in your Form to let users know something went wrong.

A practical example would be a Class that stores data to your database using a Transaction object. When an error occurs you want to rollback your transaction before you throw the Exception up to the calling Form.

A Finally... block would not suffice, because you would not know if the Transaction needs to be rolled back or committed. Handling the Exception in the Class itself is necessary, but an Exception can only be handled once and it would not be thrown to your calling Form.
There are basically two options you can consider. You either rethrow the Exception after you have handled it in your Class or you throw a new Exception, possibly passing the original Exception as an InnerException to the new Exception. The following code snippet shows the last option:

VB.NET
Private Sub btnHandlingAnExceptionMultipleTimes_Click_
	(ByVal sender As System.Object, ByVal e As System.EventArgs) _
	Handles btnHandlingAnExceptionMultipleTimes.Click
        Try
            Dim mm As New ManyMethods
            ' This method goes into four other methods!
            mm.GoIntoDeeperMethodsWithCatch()
        Catch ex As Exception
            MessageBox.Show(ex.Message & Environment.NewLine & _
                            "The method which threw me was: " & _
			 ex.TargetSite.Name & Environment.NewLine & _
                            "The method which initially threw me was: _
			 " & ex.InnerException.TargetSite.Name, _
                            Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

	Public Sub GoIntoDeeperMethodsWithCatch()
        Try
            ' This will eventually throw an exception.
            GoIntoDeeperMethods()
        Catch ex As Exception
            MessageBox.Show("Do some specific error handling here...", _
		"Some deeper method", MessageBoxButtons.OK, MessageBoxIcon.Information)
            ' Rethrow the Exception to the form so the form can handle the user interface.
            Dim newEx As New System.Exception("I am rethrown!", ex)
            Throw newEx
        End Try
    End Sub

The button Event Handler calls a method, which in turn calls other methods. Note that the second method here also has a Try... Catch... block. Eventually, you will get an Exception which will be sent to the first Catch block it finds on the stack. In this case, this will be the Catch in the GoIntoDeeperMethodsWithCatch. But further down the stack, there is another Catch block that wants to notify the user that something went wrong.

So the first Catch block handles the Exception and then throws a new Exception with the original Exception as its InnerException. The InnerException property of the Exception object can contain another Exception. So what happens here is that the GoIntoDeeperMethodsWithCatch method handles the original Exception and then throws a new Exception to the Form. The Form then has information about the new Exception and the original Exception (which is contained in the InnerException property of the new Exception). Be careful when using the InnerException property of the Exception object. If no InnerException is provided, the above code will cause a NullReferenceException. An alternative to the above code is to simply Catch ex as Exception in the GoIntoDeeperMethodsWithCatch method and then Throw ex. In this case, the original Exception is thrown to the Form or Class above. Because in this case, your Exception will not have an InnerException you would have to edit the Exception handling in the button Event Handler too. Basically you would only create a new Exception if you want to add some information to the original Exception. For example, that the first Exception has already been handled. 

Nested Try... Catch... Finally...

Sometimes, you want to do multiple error handlings in one block of code. In this case, it is possible to use nested Try... Catch... Finally... blocks.

VB.NET
Private Sub btnNestedTryCatch_Click(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles btnNestedTryCatch.Click
        Try
            ' Some code here...
            Try
                ' Some more code here...
                Dim table As New DataTable
                Try
                    ' Some more code here...
                    ' Oops! An error occurs!
                    Throw New System.Exception("I come from the third nested try.")
                    ' No Catch here, only a finally.
                Finally
                    ' This code will always execute.
                    table.Dispose()
                End Try
            Catch ex As Exception
                MessageBox.Show(ex.Message & Environment.NewLine & _
		" I was handled in the second Try... Catch... block.", _
                                Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        Catch ex As Exception
            MessageBox.Show(ex.Message & Environment.NewLine & _
		" I was handled in the first Try... Catch... block.", _
                            Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

In this example, there are three nested Try... blocks. The third one has no Catch, but a Finally only. This is no problem though, because if an Exception occurs here, it will simply be thrown to the second Try... block which does have a Catch that handles the Exception.
If an Exception occurs in the second or third nested Try... block, the Exception will never reach the first Try... block (unless it is rethrown). If the Exception occurs in the first block, it will never reach the second and third Try... blocks.

The Finally... will only be executed if your code makes it to the third Try... block. Of course you can also add Finally... blocks in the first and second Try... blocks and you can also add multiple Catches (for SqlException, IOException, etc.).

Also note that I have two variables named ex. This means that the ex variable only exists within the Catch block. Also, I declare the DataTable in the second nested Try... block which means it does not exist in the first Try... block, making it impossible to Dispose it in a Finally... block in the first Try... statement.

Using... End Using

If you are using an object that implements the IDisposable interface, you would generally do well if you actually disposed of it after you are done using it. The above examples illustrate that this can be done by using a Try... Finally... block. In the Finally... block, you can call the Dispose method of the object you are using. There is a shorter notation for these situations though.

VB.NET
Private Sub btnUsingEndUsing_Click(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles btnUsingEndUsing.Click
        Dim table1 As New DataTable
        Try
            ' Some code here...
        Finally
            table1.Dispose()
        End Try

        ' The above code actually does the same as this code!
        ' The Using... End Using block can be used with any object that
        ' implements IDisposable and makes sure that your object is disposed
        ' of, no matter what happens.
        Using table2 As New DataTable
            ' Some code here...
        End Using

        MessageBox.Show("This button does not actually do something." _
	& Environment.NewLine & "Check the source code :)", _
                        Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
    End Sub

The Using... End Using block Disposes any object for you, no matter what happens. This example only shows the shortened syntax for the Try... Finally... Dispose pattern. Nested Using... End Using blocks are also allowed, as we will see in the final example.

To Sum It Up...

This final example combines some of the above examples, using Try... Catch... Finally and Using blocks. This example does create an actual Exception, so it will not be artificially thrown from the code. Let's look at this practical example. 

VB.NET
Private Sub btnToSumItUp_Click(ByVal sender As System.Object, _
	ByVal e As System.EventArgs) Handles btnToSumItUp.Click
        Me.Cursor = Cursors.WaitCursor
        Try
            DoSomeSqlStuff()
            ' This is an alternative block of code that does the same
            ' as DoSomeSqlStuff, but looks quite differently.
            ' AlternativeDoSomeSqlStuff()
        Catch sqlEx As SqlClient.SqlException
            MessageBox.Show(sqlEx.Message, "SQL Exception", _
		MessageBoxButtons.OK, MessageBoxIcon.Error)
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Unknown exception", _
		MessageBoxButtons.OK, MessageBoxIcon.Error)
        Finally
            ' Make sure the cursor is set back to default!
            Me.Cursor = Cursors.Default
        End Try
    End Sub

    Private Sub DoSomeSqlStuff()
        Using connection As New SqlClient.SqlConnection_
	("Data Source=SomeServer;Initial Catalog=SomeDB;Integrated Security=True")
            Using cmd As New SqlClient.SqlCommand_
		("SELECT * FROM SomeTable", connection)
                connection.Open()
                Try
                    Using reader As SqlClient.SqlDataReader = cmd.ExecuteReader
                        While reader.Read
                            ' Do something... This will never happen :)
                        End While
                    End Using ' SqlReader is disposed.
                Finally
                    ' Always close the connection!
                    connection.Close()
                End Try
            End Using ' SqlCommand is disposed.
        End Using ' SqlConnection is disposed.
    End Sub

In this example, my button Event Handler tries to connect to a database. Before it does that, the cursor is transformed into a wait cursor.

In the called method, I declare a Connection object and pass a valid connection string to it. The Connection object implements IDisposable, so I can use the Using statement to declare it. Note that the connection variable only exists within the Using... End Using block. Anything I want to do with the connection should therefore be done in the Using... End Using block.

Next, I declare a Command object in the same way I declared the Connection object. I pass the connection to the Command objects constructor.
Next, I try to open the connection. This will of course never work with the provided connectionstring. The syntax is all right, but the Data Source and Initial Catalog (your SQLServer instance) simply do not exist! So, opening the connection will fail and throw an Exception.

Note that the code does not reach the Try... Finally... block and the connection will not be closed. This is all right, because we could not open it in the first place. Only after the connection is opened, it would be important to close it and thus get into the Try... Finally... block. The code will now first get to the End Using statements and dispose of your Command object and Connection object (in that order). The Exception is then handled one method up, in the button Event Handler. Here, it can be caught as an SqlException (which is the case for this Exception) or as any other Exception. After the Exception is handled, the code will go into the Finally... block and change my cursor back to default.

An alternative approach to DoSomeSqlStuff would be the following code, which does not make use of the Using... End Using statement for the Connection and Command objects.

VB.NET
Private Sub AlternativeDoSomeSqlStuff()
       Dim connection As New SqlClient.SqlConnection_
   ("Data Source=SomeServer;Initial Catalog=SomeDB;Integrated Security=True")
       Dim cmd As New SqlClient.SqlCommand("SELECT * FROM SomeTable", connection)
       Try
           connection.Open()
           Using reader As SqlClient.SqlDataReader = cmd.ExecuteReader
               While reader.Read
                   ' Do something... This will never happen :)
               End While
           End Using ' SqlReader is disposed.
       Finally
           connection.Close()
           connection.Dispose()
           cmd.Dispose()
       End Try
   End Sub

Note here that if the application fails to create a new Connection object (for example because the connection string is not syntaxically correct), the code will never jump into the Try... Finally... block, but go straight to the error handling in the button Event Handler. If the creation of the Command object fails, you would also not go into the Try... Finally... block and your Connection object would not be disposed. The chances of that happening are really very small though, so in this case it would be smart to neglect it, or you would have to add another Try... Finally... block, making your code long and difficult to read (although the Using... End Using block would be prepared for such a rare Exception). Also note that if the connection fails to open, it will still be closed in the Finally... block. Though it is not really necessary, it will not throw an Exception and it makes your code more compact and readable to not add another Try... Finally... block here. If you want, you could check the State property of your connection object before closing it though. 

Points of Interest

  • The Try... Catch... Finally... block should be used to handle Exceptions ONLY!!! Too often have I seen actual business logic in Try... Catch... blocks. This will make your software depend on Exceptions. And you do not want that! 
  • Always try to handle Exceptions at user interface level. When something goes wrong, you want to notify the user about this. Do not try to do this in underlying classes. This will make your classes less usable in other objects. Think for example that you have a Class that handles e-mailing in your application. The first form to implement e-mailing is the company products form. When the e-mailing fails and throws an Exception, you do not want your class to prompt the user that the product information could not be e-mailed. Because if you start using this Class in other forms too, let's say a sales order form, it would look kind of weird if you could not e-mail product information (you are mailing sales order information!).
  • You can handle Exceptions in underlying classes, but do not communicate them to the user from there. If you want to handle an Exception in a Class other than your user form, rethrow the Exception up the stack instead (or pass it as an InnerException to a new Exception object). Think where, when and how you want to throw and handle Exceptions.
  • Experiment with Exceptions. You can create your own Exception classes by inheriting from the System.Exception class and adding properties and/or functionality. 

History

  • 5th February, 2011: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO JUUN Software
Netherlands Netherlands
Sander Rossel is a Microsoft certified professional developer with experience and expertise in .NET and .NET Core (C#, ASP.NET, and Entity Framework), SQL Server, Azure, Azure DevOps, JavaScript, MongoDB, and other technologies.

He is the owner of JUUN Software, a company specializing in custom software. JUUN Software uses modern, but proven technologies, such as .NET Core, Azure and Azure DevOps.

You can't miss his books on Amazon and his free e-books on Syncfusion!

He wrote a JavaScript LINQ library, arrgh.js (works in IE8+, Edge, Firefox, Chrome, and probably everything else).

Check out his prize-winning articles on CodeProject as well!

Comments and Discussions

 
QuestionSending Attached mail Pin
Member 1053742526-Jan-14 23:35
Member 1053742526-Jan-14 23:35 
AnswerRe: Sending Attached mail Pin
Sander Rossel27-Jan-14 1:22
professionalSander Rossel27-Jan-14 1:22 
GeneralMy vote of 5 Pin
karenpayne16-Sep-13 5:43
karenpayne16-Sep-13 5:43 
GeneralRe: My vote of 5 Pin
Sander Rossel16-Sep-13 6:24
professionalSander Rossel16-Sep-13 6:24 
GeneralRe: My vote of 5 Pin
karenpayne16-Sep-13 6:33
karenpayne16-Sep-13 6:33 
GeneralRe: My vote of 5 Pin
Sander Rossel16-Sep-13 6:51
professionalSander Rossel16-Sep-13 6:51 
GeneralRe: My vote of 5 Pin
karenpayne16-Sep-13 7:00
karenpayne16-Sep-13 7:00 
QuestionRequires source file in C#-Please Pin
Vasanthjai12-Apr-13 22:35
Vasanthjai12-Apr-13 22:35 
AnswerRe: Requires source file in C#-Please Pin
Sander Rossel12-Apr-13 23:21
professionalSander Rossel12-Apr-13 23:21 
GeneralRe: Requires source file in C#-Please Pin
Vasanthjai13-Apr-13 1:03
Vasanthjai13-Apr-13 1:03 
QuestionUnable to use the source code file attached here Pin
Vasanthjai12-Apr-13 22:28
Vasanthjai12-Apr-13 22:28 
AnswerRe: Unable to use the source code file attached here Pin
Sander Rossel12-Apr-13 23:18
professionalSander Rossel12-Apr-13 23:18 
GeneralRe: Unable to use the source code file attached here Pin
Vasanthjai13-Apr-13 1:06
Vasanthjai13-Apr-13 1:06 
GeneralMy vote of 5 Pin
Jim Meadors4-Mar-13 20:30
Jim Meadors4-Mar-13 20:30 
GeneralRe: My vote of 5 Pin
Sander Rossel4-Mar-13 20:38
professionalSander Rossel4-Mar-13 20:38 
GeneralRe: My vote of 5 Pin
Jim Meadors5-Mar-13 19:25
Jim Meadors5-Mar-13 19:25 
GeneralRe: My vote of 5 Pin
Sander Rossel5-Mar-13 19:47
professionalSander Rossel5-Mar-13 19:47 
GeneralMy vote of 5 Pin
ProEnggSoft1-Mar-12 22:43
ProEnggSoft1-Mar-12 22:43 
GeneralRe: My vote of 5 Pin
Sander Rossel2-Mar-12 7:21
professionalSander Rossel2-Mar-12 7:21 
GeneralGood one Pin
thatraja29-Jan-12 9:10
professionalthatraja29-Jan-12 9:10 
GeneralRe: Good one Pin
Sander Rossel29-Jan-12 9:25
professionalSander Rossel29-Jan-12 9:25 
GeneralMy vote of 4 Pin
Abudreas16-Mar-11 3:17
Abudreas16-Mar-11 3:17 
GeneralUseful Pin
BillW339-Mar-11 3:21
professionalBillW339-Mar-11 3:21 
GeneralMy vote of 4 Pin
Jyothikarthik_N13-Feb-11 3:35
Jyothikarthik_N13-Feb-11 3:35 
GeneralSubtleties of rethrows Pin
User 22734467-Feb-11 22:21
User 22734467-Feb-11 22:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.