Catching Exceptions thrown within a user-written Class

  • Thread starter Thread starter Peter R. Fletcher
  • Start date Start date
P

Peter R. Fletcher

Should it be possible to do this?
In the following code fragment, fsTemp is a properly initialised
instance of a Class that I have written to do file and directory
searches. The Class's GetFolders method actually does the searching
and returns a collection of names of files corresponding to certain
criteria specified by setting other Properties of the Class instance.

Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try

If a nonexistent Drive or directory is specified, an exception is
thrown when the search runs, and I was expecting it to be caught by
the Try/Catch block round the method invocation. Instead, it is
treated as an unhandled exception wiithin the Class code.

What am I missing?
 
Are the code for the class and the code that instances the class in the same
assembly? If not then, the reason it's not working is that the exception is
being raised in the class assembly and it's not being handled (caught)
there.

Instead of letting fsTemp blow up and hoping to catch it in the code that
instances it, why not write the original class so that if a non-existant
drive is entered it (the class itself) throws a custom exception that then
can be caught by the code that uses it.

Consider this code:

Public Class FileSystemSearcher
Public Sub GetFolders(Desination)
If Not [code to see if "Destination" is good] Then
Dim GetFoldersException as New Exception("Invalid Path
Specified")
GetFoldersException.Source = Me.GetType.ToString
Throw GetFoldersException
End If
End Sub
End Class

---------------------------------------------

Now, your code that uses an instance of the class will raise the class's
custom exception:
Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try




Peter R. Fletcher said:
Should it be possible to do this?
In the following code fragment, fsTemp is a properly initialised
instance of a Class that I have written to do file and directory
searches. The Class's GetFolders method actually does the searching
and returns a collection of names of files corresponding to certain
criteria specified by setting other Properties of the Class instance.

Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try

If a nonexistent Drive or directory is specified, an exception is
thrown when the search runs, and I was expecting it to be caught by
the Try/Catch block round the method invocation. Instead, it is
treated as an unhandled exception wiithin the Class code.

What am I missing?


----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---
 
Are the code for the class and the code that instances the class in the same
assembly? If not then, the reason it's not working is that the exception is
being raised in the class assembly and it's not being handled (caught)
there.

Instead of letting fsTemp blow up and hoping to catch it in the code that
instances it, why not write the original class so that if a non-existant
drive is entered it (the class itself) throws a custom exception that then
can be caught by the code that uses it.

Consider this code:

Public Class FileSystemSearcher
Public Sub GetFolders(Desination)
If Not [code to see if "Destination" is good] Then
Dim GetFoldersException as New Exception("Invalid Path
Specified")
GetFoldersException.Source = Me.GetType.ToString
Throw GetFoldersException
End If
End Sub
End Class

---------------------------------------------

Now, your code that uses an instance of the class will raise the class's
custom exception:
Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try




Peter R. Fletcher said:
Should it be possible to do this?
In the following code fragment, fsTemp is a properly initialised
instance of a Class that I have written to do file and directory
searches. The Class's GetFolders method actually does the searching
and returns a collection of names of files corresponding to certain
criteria specified by setting other Properties of the Class instance.

Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try

If a nonexistent Drive or directory is specified, an exception is
thrown when the search runs, and I was expecting it to be caught by
the Try/Catch block round the method invocation. Instead, it is
treated as an unhandled exception wiithin the Class code.

What am I missing?


----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---




http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
 
Sorry, hit the send button on my previous reply by mistake before
writing anything!

The Class code and the form code which instances it are in different
source files in the same .Net single-Project Solution. I
thought/assumed that this meant they were in the same Assembly, but
having read some of the Help documentation on assemblies, I am not
quite so sure that it does, nor how to make sure! Everything works as
it should if I pass valid data to the Class's various Properties - I
was just trying to make it a bt more bulletproof when I ran into this
problem.

I had actually tried your suggested approach first, since it seemed to
be a better one, but I ran into the same problem (the custom exception
was treated as an unhandled exception in the Class, rather than
getting "out" to be handled in the user code).

Are the code for the class and the code that instances the class in the same
assembly? If not then, the reason it's not working is that the exception is
being raised in the class assembly and it's not being handled (caught)
there.

Instead of letting fsTemp blow up and hoping to catch it in the code that
instances it, why not write the original class so that if a non-existant
drive is entered it (the class itself) throws a custom exception that then
can be caught by the code that uses it.

Consider this code:

Public Class FileSystemSearcher
Public Sub GetFolders(Desination)
If Not [code to see if "Destination" is good] Then
Dim GetFoldersException as New Exception("Invalid Path
Specified")
GetFoldersException.Source = Me.GetType.ToString
Throw GetFoldersException
End If
End Sub
End Class

---------------------------------------------

Now, your code that uses an instance of the class will raise the class's
custom exception:
Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try




Peter R. Fletcher said:
Should it be possible to do this?
In the following code fragment, fsTemp is a properly initialised
instance of a Class that I have written to do file and directory
searches. The Class's GetFolders method actually does the searching
and returns a collection of names of files corresponding to certain
criteria specified by setting other Properties of the Class instance.

Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try

If a nonexistent Drive or directory is specified, an exception is
thrown when the search runs, and I was expecting it to be caught by
the Try/Catch block round the method invocation. Instead, it is
treated as an unhandled exception wiithin the Class code.

What am I missing?


----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---




http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
 
All files in a project, are in the same assembly. So, it sounds like you
are working within one assembly.

The code really should be written the way I've shown it. If that's not
working either, then I suspect that the code you have that actually does the
hard drive searching is the culprit.



Peter R. Fletcher said:
Sorry, hit the send button on my previous reply by mistake before
writing anything!

The Class code and the form code which instances it are in different
source files in the same .Net single-Project Solution. I
thought/assumed that this meant they were in the same Assembly, but
having read some of the Help documentation on assemblies, I am not
quite so sure that it does, nor how to make sure! Everything works as
it should if I pass valid data to the Class's various Properties - I
was just trying to make it a bt more bulletproof when I ran into this
problem.

I had actually tried your suggested approach first, since it seemed to
be a better one, but I ran into the same problem (the custom exception
was treated as an unhandled exception in the Class, rather than
getting "out" to be handled in the user code).

Are the code for the class and the code that instances the class in the same
assembly? If not then, the reason it's not working is that the exception is
being raised in the class assembly and it's not being handled (caught)
there.

Instead of letting fsTemp blow up and hoping to catch it in the code that
instances it, why not write the original class so that if a non-existant
drive is entered it (the class itself) throws a custom exception that then
can be caught by the code that uses it.

Consider this code:

Public Class FileSystemSearcher
Public Sub GetFolders(Desination)
If Not [code to see if "Destination" is good] Then
Dim GetFoldersException as New Exception("Invalid Path
Specified")
GetFoldersException.Source = Me.GetType.ToString
Throw GetFoldersException
End If
End Sub
End Class

---------------------------------------------

Now, your code that uses an instance of the class will raise the class's
custom exception:
Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try




Peter R. Fletcher said:
Should it be possible to do this?
In the following code fragment, fsTemp is a properly initialised
instance of a Class that I have written to do file and directory
searches. The Class's GetFolders method actually does the searching
and returns a collection of names of files corresponding to certain
criteria specified by setting other Properties of the Class instance.

Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try

If a nonexistent Drive or directory is specified, an exception is
thrown when the search runs, and I was expecting it to be caught by
the Try/Catch block round the method invocation. Instead, it is
treated as an unhandled exception wiithin the Class code.

What am I missing?


----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via
Encryption
=---



----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---
 
There's only one problem with your code, which is that it assumes that
InnerException is not Nothing.

Another poster replied that there might be a problem if the class and its
caller are in different assemblies. I don't know of any problems with
cross-assembly exceptions. Consider that .NET is capable of throwing you a
System.IO.IOException when you are not in the System.dll assembly.

Also, while it's ok to display the exception message to the user in a
hacked-up program, you don't want to make that the general rule. Exception
messages can be completely incomprehensible to your end-users. A favorite
example is that an attempt to register a user name which is already in use
can result in an exception message complaining about constraint violations,
duplicate keys and the like. While you might want to log that sort of
message for administration types to use later, you'd do better to tell your
user "Sorry, that user name is already in use. Please try another".

--
John Saunders
Internet Engineer
(e-mail address removed)

Peter R. Fletcher said:
Should it be possible to do this?
In the following code fragment, fsTemp is a properly initialised
instance of a Class that I have written to do file and directory
searches. The Class's GetFolders method actually does the searching
and returns a collection of names of files corresponding to certain
criteria specified by setting other Properties of the Class instance.

Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try

If a nonexistent Drive or directory is specified, an exception is
thrown when the search runs, and I was expecting it to be caught by
the Try/Catch block round the method invocation. Instead, it is
treated as an unhandled exception wiithin the Class code.

What am I missing?


----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---
 
Your code works if I identify a bad path without provoking an
exception. What doesn't work is _either_ simply allowing an exception
from the Scripting Library (which is where I am getting the file and
directory handling code) to take place _or_ (this is what I was doing
before) trapping that exception and throwing a new exception from
within the Catch block. It appears that an exception explicitly thrown
from "normal" code in the Class is correctly handled by a Try/Catch
structure in the invoking code but an exception explicitly thrown from
a Catch block in the Class is treated as if it were "trapped" within
the Class. Does this make any sense?

Even more wierdly, look at the following code fragment (from within
the Class):

Try
Dim dirtemp As New DirectoryInfo(strPath)
Call FileSearch(dirtemp, True)
Catch exc As Exception
blBadCall = True
End Try
If blBadCall Then
Dim GetFoldersException As New Exception("Invalid Path
Specified")
GetFoldersException.Source = Me.GetType.ToString
Throw GetFoldersException
End If

Even though I have here pulled the explicit throw of the exception out
of the Try/Catch structure and used your code, the thrown exception is
still treated as an unhandled exception in the Class rather than being
passed on to and handled in the invoking code. It almost seems as if
the original exception from the Scripting Library is insisting on
being handled within the Class code!

All files in a project, are in the same assembly. So, it sounds like you
are working within one assembly.

The code really should be written the way I've shown it. If that's not
working either, then I suspect that the code you have that actually does the
hard drive searching is the culprit.



Peter R. Fletcher said:
Sorry, hit the send button on my previous reply by mistake before
writing anything!

The Class code and the form code which instances it are in different
source files in the same .Net single-Project Solution. I
thought/assumed that this meant they were in the same Assembly, but
having read some of the Help documentation on assemblies, I am not
quite so sure that it does, nor how to make sure! Everything works as
it should if I pass valid data to the Class's various Properties - I
was just trying to make it a bt more bulletproof when I ran into this
problem.

I had actually tried your suggested approach first, since it seemed to
be a better one, but I ran into the same problem (the custom exception
was treated as an unhandled exception in the Class, rather than
getting "out" to be handled in the user code).

Are the code for the class and the code that instances the class in the same
assembly? If not then, the reason it's not working is that the exception is
being raised in the class assembly and it's not being handled (caught)
there.

Instead of letting fsTemp blow up and hoping to catch it in the code that
instances it, why not write the original class so that if a non-existant
drive is entered it (the class itself) throws a custom exception that then
can be caught by the code that uses it.

Consider this code:

Public Class FileSystemSearcher
Public Sub GetFolders(Desination)
If Not [code to see if "Destination" is good] Then
Dim GetFoldersException as New Exception("Invalid Path
Specified")
GetFoldersException.Source = Me.GetType.ToString
Throw GetFoldersException
End If
End Sub
End Class

---------------------------------------------

Now, your code that uses an instance of the class will raise the class's
custom exception:

Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try




Should it be possible to do this?
In the following code fragment, fsTemp is a properly initialised
instance of a Class that I have written to do file and directory
searches. The Class's GetFolders method actually does the searching
and returns a collection of names of files corresponding to certain
criteria specified by setting other Properties of the Class instance.

Try
fsTemp.GetFolders(colTemp)
Catch exc As Exception
MessageBox.Show(exc.Message & exc.InnerException.Message)
End Try

If a nonexistent Drive or directory is specified, an exception is
thrown when the search runs, and I was expecting it to be caught by
the Try/Catch block round the method invocation. Instead, it is
treated as an unhandled exception wiithin the Class code.

What am I missing?


----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet
News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000
Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---



----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---




http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
 
There's only one problem with your code, which is that it assumes that
InnerException is not Nothing.

Yes, I did correct that.
Another poster replied that there might be a problem if the class and its
caller are in different assemblies. I don't know of any problems with
cross-assembly exceptions. Consider that .NET is capable of throwing you a
System.IO.IOException when you are not in the System.dll assembly.

That occurred to me, too!
Also, while it's ok to display the exception message to the user in a
hacked-up program, you don't want to make that the general rule. Exception
messages can be completely incomprehensible to your end-users. A favorite
example is that an attempt to register a user name which is already in use
can result in an exception message complaining about constraint violations,
duplicate keys and the like. While you might want to log that sort of
message for administration types to use later, you'd do better to tell your
user "Sorry, that user name is already in use. Please try another".

Yes. As I noted elsewhere, I was engaged in bulletproofing the Class -
I would not normally display an exception message to an end-user.
 
Peter,

Your code snippets included nothing which would have led us to believe you
were using a "Scripting Library". Could you post a reproducer please?

This is the "Microsoft Scripting Runtime Library" which is included
with the .NET Framework, though it is a COM reference rather than a
native .NET one.
And if you're using unmanaged "Scripting Library" code, then you need the
following to catch exceptions thrown by it:

Try
...
Catch ' Note no parameter

End Try

I am not quite sure what you mean by "unmanaged" code. With the
reference included and the appropriate Imports statement, the
Scripting Properties and Methods behave in exactly the same way as
regular .NET Framework ones do.
I believe that this will catch unmanaged exceptions though, of course, you
won't know which exception was caught.

There is no problem _Catching_ exceptions from the Scripting runtime
in the Class which uses it, and the exception which is caught appears
to be a regular SystemException, with sensible Property settings. The
problem is that a further exception thrown after a Scripting exception
has been caught is not passed back to the user of the Class, though an
exception thrown de novo in the Class is handled correctly. Using your
Try/Catch syntax without a parameter on the Catch doesn't make any
difference to this - i.e. the newly thrown exception still doesn't get
"out" to the caller.
If you're using unmanaged "Wscript.something" code, I recommend you just
stop doing that.

See above.
Also, keep in mind that there's no magic going on here which would cause
exceptions thrown from within the Class (or Module or Assembly) to be
treated any differently. But managed vs. unmanaged code is likely to involve
various forms of "magic".

As I have noted, it seems as if the Scripting exception does something
that prevents either itself or a subsequently thrown exception from
getting "out" of the Class. I'm sure its not magic, but I would like
to understand it.
 
Peter,

Do not use the "Microsoft Scripting Runtime Library", which is not part of
the .NET Framework, and which is unmanaged (i.e., not .NET) code. Please
"don't do that".

And, please include a reproducer which we can try.
--
John Saunders
Internet Engineer
(e-mail address removed)

Peter R. Fletcher said:
This is the "Microsoft Scripting Runtime Library" which is included
with the .NET Framework, though it is a COM reference rather than a
native .NET one.


I am not quite sure what you mean by "unmanaged" code. With the
reference included and the appropriate Imports statement, the
Scripting Properties and Methods behave in exactly the same way as
regular .NET Framework ones do.


There is no problem _Catching_ exceptions from the Scripting runtime
in the Class which uses it, and the exception which is caught appears
to be a regular SystemException, with sensible Property settings. The
problem is that a further exception thrown after a Scripting exception
has been caught is not passed back to the user of the Class, though an
exception thrown de novo in the Class is handled correctly. Using your
Try/Catch syntax without a parameter on the Catch doesn't make any
difference to this - i.e. the newly thrown exception still doesn't get
"out" to the caller.


See above.


As I have noted, it seems as if the Scripting exception does something
that prevents either itself or a subsequently thrown exception from
getting "out" of the Class. I'm sure its not magic, but I would like
to understand it.



----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption
=---
 
Those two requests would appear to be mutually contradictory. If I
don't use the library, I (assume I) won't have the problem, so I
wouldn't be able to give you a reproducer. In addition, the library,
which is part of the .NET Framework package, provides functionality
which doesn't (AFAIK) exist in any pure .NET libraries in the package,
so why should I need to "not do that"?

I did write a stripped down Class using the library in an attempt to
give you a reproducer without occupying too much bandwidth, but
(curioser and curioser!) it _didn't_ reproduce the misbehaviour. I
have therefore Zipped the entire test Solution, which does, and
uploaded it to space in one of my websites. The link is
www.parish-data.com/data/FSTest.zip. I would be interested to hear
your further thoughts if you have time to look at it.
 
I am an idiot!!

I had put the "external" Try/Catch block in the click event handler of
one of two very similar (in function) buttons on my test form, but not
in that of the other, and was (of course!) persistently testing the
one _without_ the "external" exception handler in its code. The
exception was being correctly thrown in the class because there wasn't
an external handler in that pathway.
 
The library has nothing whatsoever to do with .NET. I don't know what makes
you think that it is, but it's not. Don't use it.

I'm afraid that Microsoft - or at least the people who wrote the Help
for VB .NET - would disagree with you. The FileSystemObject model is,
with the Visual Basic .NET model, and the Common Language Runtime File
methods, one of the "three possible approaches to file I/O for the
programmer" presented in the .NET documentation - see, for example,
the Help page entitled "Choosing Among File I/O Options in Visual
Basic .NET". If you want to use the FSO model, you need to import the
Scripting library, since that is where its Class definitions
apparently live (I am not quite sure why!). This necessity is also
welll documented in the Help. I initially came across a description of
this approach to file I/O in Siler and Spotts "Special Edition Using
Microsoft Visual Basic .Net" (Que Books), so someone of note in the
..NET world outside Microsoft also obviously disagrees with you.
What functionality do you think the library has that .NET does not?

A "view" of directory and file structure that works very well for what
I am doing. I am sure that you could do anything that I am doing with
it, without it, but it would be significantly more work.
 
After reading your posts, I reread the Help page I cited, together
with others referring to the FSO system, _very_ carefully. I could
find little evidence to support your contention that
the FSO model is just "mentioned....because of its familiarity to
VBScript users". It is presented as a perfectly valid way of writing
file I/O code, with advantages as well as disadvantages when compared
to the use of other approaches. Indeed, the first sentence on the page
I cited reads:
"Visual Basic .NET presents three possible approaches to file I/O for
the programmer: runtime methods contained in Visual Basic .NET;
FileSystemObject; and the Common Language Runtime File methods."
In other contexts, the .NET documentation is not generally slow to
identify older VB ways of doing things as being deprecated and/or to
recommend that .NET programmers migrate to newer approaches - it does
not appear to do that anywhere in this context.

You may well have and be able to give excellent reasons for your
recommendations against use of the FSO model in .NET programs, but I
don't think that you can adduce much support for your viewpoint from
the .NET documentation. As I mentioned in a previous post, too, your
reservations are clearly also not universal among .NET experts.
 
Back
Top