That really depends on the context.
In your example you're doing nothing else then throwing exceptions in a console
application and, as you yourself state, only at one level deep.
Using a different scenario,
Create an ASP.NET application and let it throw a couple of exceptions around
the call stack. Put a thousand or so worth of user load on the app with ACT
and measure throughput. Then get rid of the exception and do another measure.
You will see a significant increase in the throughput for the application
with less exceptions.
Regardless of the performance issue, there's a semantic and architectural
issue to consider as well.
Exceptions are errors, problems with your code that you couldn't anticipate
writing it. Consider the register user scenario.
1) A user registers for a website.
2) A users login name must be unique.
Implementing this what would be the better way? Trying to persist the user
and throw an exception if it fails or anticipate the problem in advance by
checking the input values and send feedback directly?
I would do this:
public enum RegisterStatus { Ok, LoginNameExists };
public RegisterStatus RegisterUser(User newUser) {
bool loginExists = UserRepository.CheckLoginExists(newUser.LoginName);
if ( !loginExists ) {
UserRepository.Register(newUser);
return RegisterStatus.Ok;
}
else {
return Register.LoginNameExists;
}
}
Which IMO is a much clearer. Since we expect users to enter login names that
are already used, that is not an Exceptional case and not really an error
on the users behalf, he couldn't know.
Now in another scenario:
1) We want a email class that are supposed to send emails.
2) When sending an email we expect a correct email address to be given to
us and a message to send.
Now here's a place where exceptions do come in. We expect an email adress
to our function, if we don't get it, an exception should be thrown. In this
case it's all about giving the function enough and correct information to
be able to do its job.
public void SendEmail(string to, string from, string subject, string message)
{
if ( !Validator.IsValidateEmail(to) )
throw new ArgumentException("Not a valid email", "to");
if ( !Validator.AreNotEmptyOrNullString(messsage) )
throw new ArgumentException("I need an email text to send", "message");
// Etc....
}
In this case the user are required to know how an emailadress is written,
we expect a user of an email class to know this. Therefore, not getting a
valid email adress is an Exceptional case.
For some more information about exceptions and performance / scalability,
have a browse over at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/scalenetchapt05.asp