Pieter,
The trick is to put several individual try/catch blocks around small
blocks of code. If you need that finely-grained control, a "block" may
be a single method call. RTFM and decide what you need to catch.
For instance, on the StreamReader(string) constructor, there are 5
possible exceptions that can be thrown. Based on context, each one can
mean only one thing. Do something like:
// Get string strFilename from user.
StreamReader myStream;
try
{
myStream = new StreamReader(strFilename);
}
catch (ArgumentException)
{
// The filename string was empty.
}
catch (ArgumentNullException)
{
// The filename string was null.
}
catch (FileNotFoundException)
{
// At this point, we're sure that the filename string was valid, but
there's
// no valid file at the location it points to on the filesystem.
}
catch (DirectoryNotFoundException)
{
// At this point, we're sure that the filename string was valid, but
part
// of the path that it refers to is invalid.
}
catch (IOException)
{
// At this point, we know that the format of the filename is
incorrect.
}
Similarly, just about every operation involving any I/O has a similar
canonical exception list. See the documentation and figure out exactly
what to catch and what it means for the particular functions you need.
I believe it's bad coding style to *need* to catch all of those
exceptions in most cases. A much better way to do this is to
pre-validate (contract check) every variable. For instance, the
following code:
if (strFilename == null || strFilename == String.Empty)
// Break out: the filename is invalid
will take care of the first two exceptions. File.Exists() will tell you
if the file exists or not and save you catching the other three
exceptions. No exceptions are thrown -- throwing an exception is a
highly costly process -- and you get the same information. It also has
the added benefit of saving the exceptions for real exception cases.
For instance, if the user specifies a file, then between when you
capture the filename and when you try to do something with the file,
they unplug the USB device that the file is on, that's a real
exception. It's probably one you can't handle at the level of this
method, so it should get bubbled up to the main thread and handled
there, probably by telling the user, "you've done something I didn't
expect and can't correct."
Stephan
Pieter wrote:
Hi,
For some procedures that throws exceptions, I would like to show different
messages to the user depending on what type of exception he's getting. For
instance this one: when the file is locked, I want a messagebox to tell that
the user has to close the file first.
Is there a way to identify an exception by some kind of unique number or
something like this? I don't want to identify it on the Exception Message
because some users are using French OS, and it'sj sutn ot right in my
opinion :-)
Thanks a lot in advance,
Pieter
Exemple of the exception:
Exception Source: mscorlib
Exception Type: System.IO.IOException
Exception Message: The process cannot access the file 'C:\Documents and
Settings\LBN\Desktop\Proforma.xls' because it is being used by another
process.
Exception Target Site: WinIOError
---- Stack Trace ----
System.IO.__Error.WinIOError(errorCode As Int32, maybeFullPath As String)
Ghost.exe: N 2015149
System.IO.FileStream.Init(path As String, mode As FileMode, access As
FileAccess, rights As Int32, useRights As Boolean, share As FileShare,
bufferSize As Int32, options As FileOptions, secAttrs As
SECURITY_ATTRIBUTES, msgPath As String, bFromProxy As Boolean)
Ghost.exe: N 00998
System.IO.FileStream..ctor(path As String, mode As FileMode, access As
FileAccess)
Ghost.exe: N 00057
System.Windows.Forms.SaveFileDialog.OpenFile()
Ghost.exe: N 00154
Microsoft.Reporting.WinForms.ExportDialog.PromptFi leName(fileExtension As
String)
Ghost.exe: N 00369
Microsoft.Reporting.WinForms.ExportDialog.OnExport CompleteUI(result As
ProcessThreadResult, data As Object)
Ghost.exe: N 00116