catching multiple exceptions

A

Andy B.

I have a class called Address. I need to catch exceptions from it if the
values for the properties are wrong. This is how they work:

1. Address.Type as string. Throws InvalidOperationException if not set.
2. Address.Street as string. Throws InvalidOperationException if not set.
3. Address.Line1. Has no errors since it isn't required.
4. Address.City. Throws InvalidOperationException if not set.
5. Address.State. Throws ArgumentOutOfRangeException if value is < or > than
2 characters long and ArgumentNullException if set to Nothing.
6. Address.ZipCode. Throws InvalidOperationException if not set.
7. Address.Country. See #6.

my questions:
1. Is this too many exceptions being thrown for a single class? If so, how
do you do error handling?
2. If the exceptions are ok, how do you tell the user when each one of them
changes?

'I tried this and only got the Address.State ArgumentOutOfRangeException.
Any idea what the problem is?
try
dim TestAddress as new Address()
TestAddress.State="cal" 'Get ArgumentOutOfRangeException here.
TestAddress.Street = Nothing 'Get InvalidOperationException here.
TestAddress.City = "" 'Get InvalidOperationException here.
catch ex as ArgumentOutOfRangeException
messagebox.show(ex.message)
catch ex as InvalidOperationException
messagebox.show(ex.messabe)
end try
 
A

Armin Zingler

Andy said:
I have a class called Address. I need to catch exceptions from it if
the values for the properties are wrong. This is how they work:

1. Address.Type as string. Throws InvalidOperationException if not
set. 2. Address.Street as string. Throws InvalidOperationException if not
set. 3. Address.Line1. Has no errors since it isn't required.
4. Address.City. Throws InvalidOperationException if not set.
5. Address.State. Throws ArgumentOutOfRangeException if value is < or
6. Address.ZipCode. Throws InvalidOperationException if not set.
7. Address.Country. See #6.

my questions:
1. Is this too many exceptions being thrown for a single class?

No, why? They are not thrown at the same time.
If
so, how do you do error handling?
2. If the exceptions are ok, how do you tell the user when each one
of them changes?

The exceptions? Or the property values?
'I tried this and only got the Address.State
ArgumentOutOfRangeException. Any idea what the problem is?
try
dim TestAddress as new Address()
TestAddress.State="cal" 'Get ArgumentOutOfRangeException here.
TestAddress.Street = Nothing 'Get InvalidOperationException here.
TestAddress.City = "" 'Get InvalidOperationException here.
catch ex as ArgumentOutOfRangeException
messagebox.show(ex.message)
catch ex as InvalidOperationException
messagebox.show(ex.messabe)
end try

I wonder why you catch exceptions instead of checking the value before
setting the property. The exceptions are there to catch programming errors
of the object's client (in most cases like this one).


Armin
 
A

Andy B.

2. If the exceptions are ok, how do you tell the user when each one
of them changes?

The exceptions? Or the property values?

The exceptions. But you cleared this up below (shouldn't be catching
exceptions for invalid values).
'I tried this and only got the Address.State
ArgumentOutOfRangeException. Any idea what the problem is?
try
dim TestAddress as new Address()
TestAddress.State="cal" 'Get ArgumentOutOfRangeException here.
TestAddress.Street = Nothing 'Get InvalidOperationException here.
TestAddress.City = "" 'Get InvalidOperationException here.
catch ex as ArgumentOutOfRangeException
messagebox.show(ex.message)
catch ex as InvalidOperationException
messagebox.show(ex.messabe)
end try

I wonder why you catch exceptions instead of checking the value before
setting the property. The exceptions are there to catch programming errors
of the object's client (in most cases like this one).

So it should be something like:
if(TestAddress.State = Nothing Then
'Whatever needs to be done if the value is Nothing.
else
'Whatever if it does have a value
End if

The interesting question would be: If somebody did attempt to put anything
other than 2 characters inside the Address.State property, how would you
deal with the InvalidOperationException? The other thing is that this class
can't function on its own or be a stand alone class. It is a part of a
bigger modle coming down the road a little ways from now. All of the
properties will be required to be set all at once. Either through initial
setting of the properties or through changing them from the original values.
Should I put the checks in the larger model?
 
M

Martin H.

Hello Andy,
1. Address.Type as string. Throws InvalidOperationException if not set.
2. Address.Street as string. Throws InvalidOperationException if not set.
3. Address.Line1. Has no errors since it isn't required.
4. Address.City. Throws InvalidOperationException if not set.
5. Address.State. Throws ArgumentOutOfRangeException if value is< or> than
2 characters long and ArgumentNullException if set to Nothing.
6. Address.ZipCode. Throws InvalidOperationException if not set.
7. Address.Country. See #6.

I wouldn't do too much checking. From your point 7 I see that you have a
country property. Please keep in mind that not all countries follow the
American way of handling addresses. Some have several lines for the
address (e.g. Hong Kong or India) or they don't use state abbreviations
(e.g. Germany usually doesn't) and if they do they might be longer.

The zip code might also be shorter than in the US (maybe just 4 numbers
as in Switzerland for example). Oh, and in case you have an area code
field: The area codes might also be shorter or longer than in the US
(Germany e.g. has between 3 and 5 digits (030 for Berlin, 0234 for
Bochum, 05251 for Paderborn).

As an example, I give you one of my old Hongkong address (I now live in
Berlin, Germany - so this address is completely outdated... ;) ):

Martin H.
Flat D, 14/F
Hoi Ning Mansion
Riviera Gardens
Tsuen Wan, N.T.
Hong Kong

Phone: +852 6349-7208

So if you want to check the data I suggest to do that just when the user
clicks on a button as (s)he might just be annoyed from getting 6 error
messages.

Best regards,

Martin
 
J

Jack Jackson

I have a class called Address. I need to catch exceptions from it if the
values for the properties are wrong. This is how they work:

1. Address.Type as string. Throws InvalidOperationException if not set.
2. Address.Street as string. Throws InvalidOperationException if not set.
3. Address.Line1. Has no errors since it isn't required.
4. Address.City. Throws InvalidOperationException if not set.
5. Address.State. Throws ArgumentOutOfRangeException if value is < or > than
2 characters long and ArgumentNullException if set to Nothing.
6. Address.ZipCode. Throws InvalidOperationException if not set.
7. Address.Country. See #6.

my questions:
1. Is this too many exceptions being thrown for a single class? If so, how
do you do error handling?
2. If the exceptions are ok, how do you tell the user when each one of them
changes?

'I tried this and only got the Address.State ArgumentOutOfRangeException.
Any idea what the problem is?
try
dim TestAddress as new Address()
TestAddress.State="cal" 'Get ArgumentOutOfRangeException here.
TestAddress.Street = Nothing 'Get InvalidOperationException here.
TestAddress.City = "" 'Get InvalidOperationException here.
catch ex as ArgumentOutOfRangeException
messagebox.show(ex.message)
catch ex as InvalidOperationException
messagebox.show(ex.messabe)
end try

The "problem" is that once you cause an exception, no more code beyond
that point gets executed. Exceptions are not collected and thrown at
some later time. When you cause the first exception (by setting state
to an invalid value), none of the following code executes.

Another approach would be to not throw an exception on each property
setting, but have a Validate method in the object that validates the
entire object. In that case I would probably create my own exception
object and throw it. It could have, as part of its message,
information about everything that was wrong.

In fact, as someone else pointed out, it may not be possible to
validate each piece independently since not all countries have the
same rules.
 
A

Andy B.

So the address class should just be a carrier of data. Whatever needs to be
validated should be done at the bigger level (since an address can't exist
by itself) it will be part of another class.
 
A

Andy B.

Jack Jackson said:
The "problem" is that once you cause an exception, no more code beyond
that point gets executed. Exceptions are not collected and thrown at
some later time. When you cause the first exception (by setting state
to an invalid value), none of the following code executes.

Another approach would be to not throw an exception on each property
setting, but have a Validate method in the object that validates the
entire object. In that case I would probably create my own exception
object and throw it. It could have, as part of its message,
information about everything that was wrong.

In fact, as someone else pointed out, it may not be possible to
validate each piece independently since not all countries have the
same rules.

Would you put the validate method inside the address class or in the
complete object. For an example: I have address and ContactPerson classes.
Now I want to create a Venue and a Host. Each one of these classes (venue
and Host) would have their own properties as well as using address and
ContactPerson collections. So we would have:

public class Venue

'fields
dim _Name as string 'Venue name
dim _Addresses as Collection(Of Address) 'Collection of addresses the Venue
has
dim _ContactPeople as Collection(OF ContactPerson) 'Contact people at the
Venue

'properties...

End class

Would I put the validate operations here? You talked about throwing an
exception for the entire object if it didn't validate that included
everything that was wrong with the validation. How would you do something
like that?
 
M

Martin H.

Hello Andy,
Would you put the validate method inside the address class or in the
complete object. For an example: I have address and ContactPerson classes.
Now I want to create a Venue and a Host. Each one of these classes (venue
and Host) would have their own properties as well as using address and
ContactPerson collections. So we would have:

public class Venue

'fields
dim _Name as string 'Venue name
dim _Addresses as Collection(Of Address) 'Collection of addresses the Venue
has
dim _ContactPeople as Collection(OF ContactPerson) 'Contact people at the
Venue

'properties...

End class

Would I put the validate operations here? You talked about throwing an
exception for the entire object if it didn't validate that included
everything that was wrong with the validation. How would you do something
like that?

If I had to do such a thing, I would do something like this:

Private Sub Cmd_Execute(...)Handles ...

If Address.Country = "United States" Or Address.Country = "Canada" Then
If Len(Trim(Address.Street))=0 or Len(Trim(Address.City))= 0 _
Or Not Len(Trim(Address.State))=2 Or Len(Trim(Address.ZipCode) _
< 5 Then
MsgBox ("Error")
Else
DoYourStuff()
End
ElseIf Len(Trim(Address.Street))=0 or Len(Trim(Address.City))= 0 _
Or Len(Trim(Address.Country)=0 Then
MsgBox ("Error")
Else
DoYourStuff()
End If
End Sub

However, if you need to validate the Address more than one time, it
would be a good idea to put it into the class as a separate method, e.g.
like this:

Class Address
Dim Street As String=""
Dim AddressLine1 As String=""
Dim AddressLine2 As String=""
Dim City As String=""
Dim State As String=""
Dim ZipCode As String=""
Dim Country As String=""

Public Function Validate() As Boolean
Dim retVal As Boolean
retVal = True
If Address.Country = "United States" Or Address.Country = "Canada" Then
If Len(Trim(Address.Street))=0 or Len(Trim(Address.City))= 0 _
Or Not Len(Trim(Address.State))=2 Or Len(Trim(Address.ZipCode) _
< 5 Then
retVal = False
End
ElseIf Len(Trim(Address.Street))=0 or Len(Trim(Address.City))= 0 _
Or Len(Trim(Address.Country)=0 Then
retVal = False
End If

Return retVal
End Function

'...Put your properties here...
End Class

You could then check when you want to execute the operation:
Private Sub Cmd_Execute(...)Handles ...
If Not Address.Validate() Then
MsgBox ("Oops! Address Error")
Else
DoYourStuff()
End If
End Sub

Best regards,

Martin
 
C

Cor Ligthert[MVP]

Andy,

In my idea are you mixing up things.
You can make in your class that is validating the properties an exception
that will be throwed.

However, an exception will only be throwed once to be catchable.
You will see that the result of what you are doing will be more work then
what you had in mind.

As far as I understand you, is it in your case more simple to simple create
a validation method in your class and let that return an array of found
errors.

Be aware that you are working on a not normal approach.

Cor
 
J

Jack Jackson

Would you put the validate method inside the address class or in the
complete object. For an example: I have address and ContactPerson classes.
Now I want to create a Venue and a Host. Each one of these classes (venue
and Host) would have their own properties as well as using address and
ContactPerson collections. So we would have:

public class Venue

'fields
dim _Name as string 'Venue name
dim _Addresses as Collection(Of Address) 'Collection of addresses the Venue
has
dim _ContactPeople as Collection(OF ContactPerson) 'Contact people at the
Venue

'properties...

End class

Would I put the validate operations here? You talked about throwing an
exception for the entire object if it didn't validate that included
everything that was wrong with the validation. How would you do something
like that?

You don't want to duplicate code. If addresses are validated the same
way no matter where they are, then the validation code should be part
of the Address class.

If you use a Validate method, then I wouldn't throw an exception, just
return an error flag. Something like:

Function Validate(ByRef msg As String) As Boolean

Dim err As Boolean = False

msg = ""

If Street = ""
err = True
msg = msg + "Invalid Street" + Environment.NewLine
End If

If City = ""
err = True
msg = msg + "Invalid City" + Environment.NewLine
End If
...

Return err

If you do want to throw an exception, you could have similar code that
creates and throws an exception at the end.
 
M

Michael C

Andy B. said:
So the address class should just be a carrier of data. Whatever needs to
be validated should be done at the bigger level (since an address can't
exist by itself) it will be part of another class.

No, I think the address class should validate itself. There are several ways
to do it. One way is to accept the values entered no matter what they are
and have seperate properties the gui can test to determine if there are
errors. Then if the user saves they will get an exception. However this
should never happen as the GUI should warn the user their address is invalid
and stop them saving.

Michael
 
A

Andy B.

Michael C said:
No, I think the address class should validate itself. There are several
ways to do it. One way is to accept the values entered no matter what they
are and have seperate properties the gui can test to determine if there
are errors. Then if the user saves they will get an exception. However
this should never happen as the GUI should warn the user their address is
invalid and stop them saving.

Michael

Somebody I know told me that I should make all of the properties and fields
private and have the Address do everything internally. The only 2 public
methods would be the constructer and an override ToString to return the
entire valid address. They said that this keeps unauthorized access from the
address if it is valid and forces the user to go through a routine to
recreate the address if it is invalid. At the best in this case I told them
that the properties have to be public since they bind to TextBoxes and
labels. Then they said I could leave the properties all read only and still
force them through the constructer to do anything with the address. What do
you think about that idea? I was thinking have Street, Line2, City, State,
Country, ZipCode and Type read/write. Have an IsValid property that is read
only that returns true/false. Have 2 methods Validate that validates the
address and sets IsValid to whatever it needs to be set to. Have GetErrors
method return all of the errors if IsValid is false.
 
C

Cor Ligthert[MVP]

Old fashion

Cor

Andy B. said:
Somebody I know told me that I should make all of the properties and
fields private and have the Address do everything internally. The only 2
public methods would be the constructer and an override ToString to return
the entire valid address. They said that this keeps unauthorized access
from the address if it is valid and forces the user to go through a
routine to recreate the address if it is invalid. At the best in this case
I told them that the properties have to be public since they bind to
TextBoxes and labels. Then they said I could leave the properties all read
only and still force them through the constructer to do anything with the
address. What do you think about that idea? I was thinking have Street,
Line2, City, State, Country, ZipCode and Type read/write. Have an IsValid
property that is read only that returns true/false. Have 2 methods
Validate that validates the address and sets IsValid to whatever it needs
to be set to. Have GetErrors method return all of the errors if IsValid is
false.
 
M

Michael C

Andy B. said:
Somebody I know told me that I should make all of the properties and
fields private and have the Address do everything internally. The only 2
public methods would be the constructer and an override ToString to return
the entire valid address. They said that this keeps unauthorized access
from the address if it is valid and forces the user to go through a
routine to recreate the address if it is invalid. At the best in this case
I told them that the properties have to be public since they bind to
TextBoxes and labels. Then they said I could leave the properties all read
only and still force them through the constructer to do anything with the
address. What do you think about that idea?

Sounds a bit odd to me. If a user has the ability to edit an address on
screen then they should be able to edit your address object. If there is a
situation where the user can only delete the object and recreate then what
this person said would make sense but surely you're not going to make the
user retype an entire address just because they mispelt the street name. I
don't see how the constructor method adds anything anyway, you can still
achieve the same thing without it.
I was thinking have Street, Line2, City, State, Country, ZipCode and Type
read/write. Have an IsValid property that is read only that returns
true/false. Have 2 methods Validate that validates the address and sets
IsValid to whatever it needs to be set to. Have GetErrors method return
all of the errors if IsValid is false.

Sounds ok to me, the only thing I would say is that you should not have an
IsValid private field but just have it check of errorcount is greater than
zero.

Michael
 
C

Cor Ligthert[MVP]

It is a kind of punch card processing approach (or magnic tape with records)

Cor
 
M

Michael C

Cor Ligthert said:
It is a kind of punch card processing approach (or magnic tape with
records)

It can be very time consuming but can't you automate it? (to some degree at
least). What is the alternative?

Michael
 
A

Andy B.

I was thinking have Street, Line2, City, State, Country, ZipCode and Type
Sounds ok to me, the only thing I would say is that you should not have an
IsValid private field but just have it check of errorcount is greater than
zero.

Why not have a private IsValid field?
 
M

Michael C

Andy B. said:
Why not have a private IsValid field?

It's a duplication of data, you're storing the fact that it's not valid by
having more than 1 item in the errors collection and and the IsValid field.
Whenever you store something twice there is always the chance they'll get
different values in them.

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top