Would it be a good idea to replace the if statements with try-catch in the following usecases (performance and readability wise?):
Example 1
public static void AddInitializable(GameObject initializable)
{
if(!HasInstance)
{ // this should only happen if I have forgotten to instantiate the GameManager manually
Debug.LogWarning("GameManager not found.");
return;
}
instance.initializables.Add(initializable);
initializable.SetActive(false);
}
public static void AddInitializable2(GameObject initializable)
{
try
{
instance.initializables.Add(initializable);
initializable.SetActive(false);
}
catch
{
Debug.LogWarning("GameManager not found.");
}
}
Example 2
public static void Init(int v)
{
if(!HasInstance)
{// this should happen only once
instance = this;
}
instance.alj = v;
}
public static void Init2(int v)
{
try
{
instance.alj = v;
}
catch
{
instance = this;
Init(v);
}
}
Edit:
Question 2: How many Exceptions can I get to be still performance positive?
It depends.
Try-blocks are generally cheap, so when the exception is not thrown, that would be an acceptable solution. But: In your case, if the condition is not satisfied (meaning the thing was not initialized before that method was called), this is a programming error, not something that should ever happen in the finished program. It is perfectly valid that such errors crash the program. Makes spotting the bugs and fixing them much easier in development, and avoids that you silently hide it (in example 1, you silently don't do anything, which might cause confusing behavior later).
So: If it would be a programming error, don't use an exception handler, nor a test (except maybe an Assert). Just let the program crash (with a NullReferenceException in this case).
I would agree with PMF: Depends!
On your specific use case and in specific whether something is your fault or something you can't control / predict.
So in general I'd say there are three ways of how to handle stuff that isn't behaving as expected
A) let throw an exception to indicate that this is really bad and there is no way to recover => and most probably crash your app
This usually makes totally sense on development time because while debugging you explicitly want your app to crash so you can find and fix the issue.
This should be happening for everything where the cause is basically something that you messed up and can be fixed by you. (In your case instance not initialized correctly)
B) return something e.g. false to indicate that something went bad but allow this to be handled by the code and e.g. try something else.
In my eyes this should be the preferred way of dealing with stuff you can't control yourself like e.g. user input and other unpredictable conditions like internet connectivity etc.
C) Just ignore it and do nothing at all.
Depends of course on what exactly you are doing but this should actually happen almost never. For a User this can be extremely frustrating and also for you as developer it makes debugging hard to impossible!
In combination with B of course this is valid since something else will already have delt with the issue.
And to add just in general unless you work on some core / reused library I would actually never throw exceptions myself except you are re-throwing caught ones to add additional debugging information. This basically falls under "you can't control" how others will use your library -> this basically from your perspective falls under user input ;)
Now all three options can be achieved by try - catch or if checks internally of course and it depends on your specific case which way you want to go.
Some thoughts of mine on this
Readability wise I would prefer the if already alone because it makes clear exactly which condition is checked. When I see a try - catch I don't know exactly at which point which exact exception might be thrown on first glance.
Thus using try - catch as a replacement for if just obscures what exactly is failing and makes debugging hard to impossible
Exceptions are quite expensive! So performance wise I would say use if wherever possible.
There are cases though - and in my opinion these are the only ones where try - catch would be allowed - where you use a library and there simply is no way to prevent an exception.
Example: FileIO
the file you want to access does not exist
-> You don't need try - catch for this (in my eyes it would be the lazy way). This is something you can and should actually check first if(!File.Exists(...)) so your program can correctly deal with it and handle that case (e.g. you might want to tell the user instead of simply crash or doing nothing).
The file is currently opened by another program so you can't write to it.
-> There is no way to find this out beforehand. You will get an exception and can't avoid it. Here you want to try - catch in order to still allow your code to deal with such case (as before e.g. tell the user instead of simply crash).
But then how you actually deal with them again depends:
If you e.g. use some hardcoded paths and these files definitely should be there -> Exception because it means you as developer messed something up.
If the path comes from user input -> Catch because this is something you as developer can't control but don't just want your app to crash, rather show a hint to the user that he messed it up.
Now in your use case the Example 1 both of your solutions seem pretty bad to me. You go with the last option C and just ignore the call - a user won't see the warning and also a developer might just not note / ignore it.
You definitely want to get an Exception here if this means that your app will not behave correctly and not catch it at all!
In general there is no need for a special bool flag. I would rather go with
if(instance == null)
{
Debug.LogError(...);
return;
}
Because this is most probably a more severe error not only a warning so it at least gains visibility.
In your Example 2 you actually have kind of a lazy initialization anyway so either way the call itself is basically valid.
In such case though again this is something you can easily check and I would not wait for an exception (especially not simply any) because I already know that there definitely will be one at least once.
In my opinion this should rather be
if(instance == null)
{
// I have put `???` because, well, in a "static" method there is no "this" so
// I wonder where the instance should come from in that case ;)
instance = ???;
}
instance.alj = v;
So you're kind of along the right lines here.
Unless you are in dire need of increasing performance, don't try to optimize, and if you do need to optimize, make sure you're doing it right (exceptions are more expensive that if statements, especially if you know they're going to happen)
The first example you've given, I can kind of get behind. You're making the assumption that something was initialized, and if it turns out it wasn't, throw an error. You're logging it, it's ok, you initialize it and you'll probably never have to worry about that exception again.
The second example you've given is a big no no. You should not use exceptions to fall into other logic in your application. Instead, in the Init() method, just always have the line 'instance = this', don't do the if statement. Once you know it's initialized, there should never be a reason for it to throw an exception when used.
Of course, don't go crazy with this, exceptions should only be used for exceptional circumstances. If you write your code and are thinking 'Hmm, so it could be either A scenario or B scenario, and in B scenario I want this to happen, so I'll throw an exception' that's completely the wrong line of thinking. Instead it should be 'Hmm, so all this will happen, but just in case something breaks, I'll put it in a try catch and log it, as who knows, I'm not infallible'
You can see how I've applied the above logic to your two examples,
To my point of view, this is not a good idea.
We usually use try catch when we know what kind of exceptions will appear in the context, and hence a catch without exception type is not a good practice. Moreover, try catch is not expensive only if the exception rarely happens.
In your scenario, since you already know the only problem is that the property HasInstance may be false, you could directly check it with if statement. Using try catch seems more like a cost here, although it works. This seems like you are expecting an error, and you just ignore that error because its message does not matter.
Besides, I see you are using Unity and are creating a singleton GameManager, and actually I think the singleton pattern here might not be quite correct.
For example, if you use the code like this, actually there is virtually no possibility it does not have an instance if you treat your scene and gameobjects properly :)
Exceptions are there when an "impossible" state occurs in your interfaces (Not the keyword - just the word), if you have to try - catch inside your business logic, your design is compromised.
In this case, you would likely gain both extendability, and readability, if you implement the slightly miss-named null-object pattern. (Should be called default object pattern)
And simply never be able to pass a null'ed interface to the method.
So:
public interface IGameObject {
void Activate(instance initializable);
}
public class GameObjectDefault : IGameObject {
public void Activate(instance initializable){
--Does nothing on purpose
}
}
public class GameObjectReal : IGameObject {
private Instance _instance;
public GameObjectReal(Instance instance)
{
_instance = instance;
}
public void Activate(IGameObject initializable) {
_instance.initializables.Add(initializable);
--Do whatever you need to do to the object
}
}
This is pseudo, because I can't see your whole system.
But this way, if you initialize all game objects as DefaultGameObjects, your activate or any other method, will just do nothing.
Now, there is no reason to check for null.
And no reason to do a try catch. Your impossible state, is now, literally, impossible.
Related
I've read a bit around, trying to figure out when to use assertions and exceptions appropriately, but there's still something I'm missing to the big picture. Probably I just need more experience, so I'd like to bring some simple examples to better comprehend in what situations I should use use what.
Example 1: let us start with the classical situation of an invalid value. For example I have the following class, in which both fields must be positive:
class Rectangle{
private int height;
private int length;
public int Height{
get => height;
set{
//avoid to put negative heights
}
}
//same thing for length
}
Let me remark that I am not talking about how to deal with user input in this example, since I could just make a simple control flow for that. Though, I am facing with the idea that somewhere else there may be some unexpected error and I want this to be detected since I don't want an object with invald values. So I can:
Use Debug.Assert and just stop the program if that happens, so that I can correct possible errors when they come.
Throw an ArgumentOutOfRangeException to basically do the same thing? This feels wrong, so I should use that only if I know I'm going to handle it somewhere. Though, if I know where to handle the exception, shouldn't I fix the problem where it lies? Or maybe it is meant for things that may happen but you cannot control directly in your code, like an user input (well that can be dealt with, without an exception, but maybe something else can't) or loading data?
Question: did I get the meaning of assertions and exceptions right? Also, could you please give an example in which handling exceptions can be useful (because something you cannot control before happens)? I cannot figure out what else, beyond the cases I mentioned, can happen, but I clearly still lack experience here.
To expand a bit my question: I can think of a variety of reasons why an exception can be thrown, like a NullReferenceException, an IndexOutOfBoundsException, the IO exceptions like DirectoryNotFoundException or FileNotFoundException, etc. Though, I cannot figure out situations in which handling them becomes useful, apart from simply stopping the program (in which case, shouldn't an assertion be used?) or giving a simple message of where the problem has occured. I know even this is useful and exceptions are also meant to categorize "errors" and give clue to how to fix them. Though, is a simple message really all they are useful to? That's sounds fishy, so I'll stick with the "I've never faced a proper situation, 'cause of experience" mantra.
Example 2: let us now talk about the user input, using the first example. As I've anticipated, I won't use an exception just to check that the values are positive, as that's a simple control flow. But what happens if the user inputs a letter? Should I handle an exception here (maybe a simple ArgumentException) and give a message in the catch block? Or it can be avoided, too, through control flow (check if input is of type int, or something like that)?
Thanks to anyone who will clear my lingering doubts.
Throw an ArgumentOutOfRangeException to basically do the same thing? This feels wrong, so I should use that only if I know I'm going to handle it somewhere. Though, if I know where to handle the exception, shouldn't I fix the problem where it lies?
Your reasoning is pretty good here, but not quite right. The reason you're struggling is because exceptions are used for four things in C#:
boneheaded exceptions. A boneheaded exception is something like "invalid argument" when the caller could have known that the argument is invalid. If a boneheaded exception is thrown then the caller has a bug that should be fixed. You never have a catch(InvalidArgumentException) outside of a test case because it should never be thrown in production. These exceptions exist to help your callers write correct code by telling them very loudly when they've made a mistake.
vexing exceptions are boneheaded exceptions where the caller cannot know that the argument is invalid. These are design flaws in APIs and should be eliminated. They require you to wrap API calls with try-catches to catch what looks like an exception that should be avoided, not caught. If you find that you're writing APIs that require the caller to wrap calls in a try-catch, you're doing something wrong.
fatal exceptions are exceptions like thread aborted, out of memory, and so on. Something terrible has happened and the process cannot continue. There is very little point in catching these because there's not much you can do to improve the situation, and you might make it worse.
exogenous exceptions are things like "the network cable is unplugged". You expected the network cable to be plugged in; it is not, and there is no way you could have checked earlier to see if it was, because the time of checking and the time of using are different times; the cable could be unplugged between those two times. You have to catch these.
Now that you know what the four kinds of exceptions are, you can see what the difference is between an exception and an assertion.
An assertion is something that must logically be true always, and if it is not, then you have a bug that should be fixed. You never assert that the network cable is plugged in. You never assert that a caller-supplied value is not null. There should never be a test case that causes an assertion to fire; if there is, then the test case has discovered a bug.
You assert that after your in-place sort algorithm runs, the smallest element in a non-empty array is at the beginning. There should be no way that can be false, and if there is, you have a bug. So assert that fact.
A throw by contrast is a statement, and every statement should have a test case which exercises it. "This API throws when passed null by a buggy caller" is part of its contract, and that contract should be testable. If you find you're writing throw statements that have no possible test case that verifies that they throw, consider changing it to an assertion.
And finally, never pass invalid arguments and then catch a boneheaded exception. If you're dealing with user input, then the UI layer should be verifying that the input is syntactically valid, ie, numbers where numbers are expected. The UI layer should not be passing possibly-unvetted user code to a deeper API and then handling the resulting exception.
I see it that way. Assertions are for programmers. Exceptions are for users. You can have places in your code that you expect specific value. Then you can put assertion, for example:
public int Age
{
get { return age; }
set
{
age = value;
Debug.Assert(age == value);
}
}
This is just example. So if age != value there is no exception. But "hey programmer, something strange may have happened, look at this part of code".
You use exception when application don't know how to react in a specific situation. For example:
public int Divide(int a, int b)
{
Debug.Assert(b != 0); //this is for you as a programmer, but if something bad happened, user won't see this assert, but application also doesn't know what to do in situation like this, so you will add:
if(b == 0)
throw SomeException();
}
And SomeException might be handled somewhere else in your application.
To avoid all standard-answers I could have Googled on, I will provide an example you all can attack at will.
C# and Java (and too many others) have with plenty of types some of ‘overflow’ behaviour I don’t like at all (e.g type.MaxValue + type.SmallestValue == type.MinValue for example : int.MaxValue + 1 == int.MinValue).
But, seen my vicious nature, I’ll add some insult to this injury by expanding this behaviour to, let’s say an Overridden DateTime type. (I know DateTime is sealed in .NET, but for the sake of this example, I’m using a pseudo language that is exactly like C#, except for the fact that DateTime isn’t sealed).
The overridden Add method:
/// <summary>
/// Increments this date with a timespan, but loops when
/// the maximum value for datetime is exceeded.
/// </summary>
/// <param name="ts">The timespan to (try to) add</param>
/// <returns>The Date, incremented with the given timespan.
/// If DateTime.MaxValue is exceeded, the sum wil 'overflow' and
/// continue from DateTime.MinValue.
/// </returns>
public DateTime override Add(TimeSpan ts)
{
try
{
return base.Add(ts);
}
catch (ArgumentOutOfRangeException nb)
{
// calculate how much the MaxValue is exceeded
// regular program flow
TimeSpan saldo = ts - (base.MaxValue - this);
return DateTime.MinValue.Add(saldo)
}
catch(Exception anyOther)
{
// 'real' exception handling.
}
}
Of course an if could solve this just as easy, but the fact remains that I just fail to see why you couldn’t use exceptions (logically that is, I can see that when performance is an issue that in certain cases exceptions should be avoided).
I think in many cases they are more clear than if-structures and don’t break any contract the method is making.
IMHO the “Never use them for regular program flow” reaction everybody seems to have is not that well underbuild as the strength of that reaction can justify.
Or am I mistaken?
I've read other posts, dealing with all kind of special cases, but my point is there's nothing wrong with it if you are both:
Clear
Honour the contract of your method
Shoot me.
Have you ever tried to debug a program raising five exceptions per second in the normal course of operation ?
I have.
The program was quite complex (it was a distributed calculation server), and a slight modification at one side of the program could easily break something in a totally different place.
I wish I could just have launched the program and wait for exceptions to occur, but there were around 200 exceptions during the start-up in the normal course of operations
My point : if you use exceptions for normal situations, how do you locate unusual (ie exceptional) situations ?
Of course, there are other strong reasons not to use exceptions too much, especially performance-wise
Exceptions are basically non-local goto statements with all the consequences of the latter. Using exceptions for flow control violates a principle of least astonishment, make programs hard to read (remember that programs are written for programmers first).
Moreover, this is not what compiler vendors expect. They expect exceptions to be thrown rarely, and they usually let the throw code be quite inefficient. Throwing exceptions is one of the most expensive operations in .NET.
However, some languages (notably Python) use exceptions as flow-control constructs. For example, iterators raise a StopIteration exception if there are no further items. Even standard language constructs (such as for) rely on this.
My rule of thumb is:
If you can do anything to recover from an error, catch exceptions
If the error is a very common one (eg. user tried to log in with the wrong password), use returnvalues
If you can't do anything to recover from an error, leave it uncaught (Or catch it in your main-catcher to do some semi-graceful shutdown of the application)
The problem I see with exceptions is from a purely syntax point of view (I'm pretty sure the perfomance overhead is minimal). I don't like try-blocks all over the place.
Take this example:
try
{
DoSomeMethod(); //Can throw Exception1
DoSomeOtherMethod(); //Can throw Exception1 and Exception2
}
catch(Exception1)
{
//Okay something messed up, but is it SomeMethod or SomeOtherMethod?
}
.. Another example could be when you need to assign something to a handle using a factory, and that factory could throw an exception:
Class1 myInstance;
try
{
myInstance = Class1Factory.Build();
}
catch(SomeException)
{
// Couldn't instantiate class, do something else..
}
myInstance.BestMethodEver(); // Will throw a compile-time error, saying that myInstance is uninitalized, which it potentially is.. :(
Soo, personally, I think you should keep exceptions for rare error-conditions (out of memory etc.) and use returnvalues (valueclasses, structs or enums) to do your error checking instead.
Hope I understood your question correct :)
A first reaction to a lot of answers :
you're writing for the programmers and the principle of least astonishment
Of course! But an if just isnot more clear all the time.
It shouldn't be astonishing eg : divide (1/x) catch (divisionByZero) is more clear than any if to me (at Conrad and others) . The fact this kind of programming isn't expected is purely conventional, and indeed, still relevant. Maybe in my example an if would be clearer.
But DivisionByZero and FileNotFound for that matter are clearer than ifs.
Of course if it's less performant and needed a zillion time per sec, you should of course avoid it, but still i haven't read any good reason to avoid the overal design.
As far as the principle of least astonishment goes : there's a danger of circular reasoning here : suppose a whole community uses a bad design, this design will become expected! Therefore the principle cannot be a grail and should be concidered carefully.
exceptions for normal situations, how do you locate unusual (ie exceptional) situations ?
In many reactions sth. like this shines trough. Just catch them, no? Your method should be clear, well documented, and hounouring it's contract. I don't get that question I must admit.
Debugging on all exceptions : the same, that's just done sometimes because the design not to use exceptions is common. My question was : why is it common in the first place?
Before exceptions, in C, there were setjmp and longjmp that could be used to accomplish a similar unrolling of the stack frame.
Then the same construct was given a name: "Exception". And most of the answers rely on the meaning of this name to argue about its usage, claiming that exceptions are intended to be used in exceptional conditions. That was never the intent in the original longjmp. There were just situations where you needed to break control flow across many stack frames.
Exceptions are slightly more general in that you can use them within the same stack frame too. This raises analogies with goto that I believe are wrong. Gotos are a tightly coupled pair (and so are setjmp and longjmp). Exceptions follow a loosely coupled publish/subscribe that is much cleaner! Therefore using them within the same stack frame is hardly the same thing as using gotos.
The third source of confusion relates to whether they are checked or unchecked exceptions. Of course, unchecked exceptions seem particularly awful to use for control flow and perhaps a lot of other things.
Checked exceptions however are great for control flow, once you get over all the Victorian hangups and live a little.
My favorite usage is a sequence of throw new Success() in a long fragment of code that tries one thing after the other until it finds what it is looking for. Each thing -- each piece of logic -- may have arbritrary nesting so break's are out as also any kind of condition tests. The if-else pattern is brittle. If I edit out an else or mess up the syntax in some other way, then there is a hairy bug.
Using throw new Success() linearizes the code flow. I use locally defined Success classes -- checked of course -- so that if I forget to catch it the code won't compile. And I don't catch another method's Successes.
Sometimes my code checks for one thing after the other and only succeeds if everything is OK. In this case I have a similar linearization using throw new Failure().
Using a separate function messes with the natural level of compartmentalization. So the return solution is not optimal. I prefer to have a page or two of code in one place for cognitive reasons. I don't believe in ultra-finely divided code.
What JVMs or compilers do is less relevant to me unless there is a hotspot. I cannot believe there is any fundamental reason for compilers to not detect locally thrown and caught Exceptions and simply treat them as very efficient gotos at the machine code level.
As far as using them across functions for control flow -- i. e. for common cases rather than exceptional ones -- I cannot see how they would be less efficient than multiple break, condition tests, returns to wade through three stack frames as opposed to just restore the stack pointer.
I personally do not use the pattern across stack frames and I can see how it would require design sophistication to do so elegantly. But used sparingly it should be fine.
Lastly, regarding surprising virgin programmers, it is not a compelling reason. If you gently introduce them to the practice, they will learn to love it. I remember C++ used to surprise and scare the heck out of C programmers.
The standard anwser is that exceptions are not regular and should be used in exceptional cases.
One reason, which is important to me, is that when I read a try-catch control structure in a software I maintain or debug, I try to find out why the original coder used an exception handling instead of an if-else structure. And I expect to find a good answer.
Remember that you write code not only for the computer but also for other coders. There is a semantic associated to an exception handler that you cannot throw away just because the machine doesn't mind.
Josh Bloch deals with this topic extensively in Effective Java. His suggestions are illuminating and should apply to .NET as well (except for the details).
In particular, exceptions should be used for exceptional circumstances. The reasons for this are usability-related, mainly. For a given method to be maximally usable, its input and output conditions should be maximally constrained.
For example, the second method is easier to use than the first:
/**
* Adds two positive numbers.
*
* #param addend1 greater than zero
* #param addend2 greater than zero
* #throws AdditionException if addend1 or addend2 is less than or equal to zero
*/
int addPositiveNumbers(int addend1, int addend2) throws AdditionException{
if( addend1 <= 0 ){
throw new AdditionException("addend1 is <= 0");
}
else if( addend2 <= 0 ){
throw new AdditionException("addend2 is <= 0");
}
return addend1 + addend2;
}
/**
* Adds two positive numbers.
*
* #param addend1 greater than zero
* #param addend2 greater than zero
*/
public int addPositiveNumbers(int addend1, int addend2) {
if( addend1 <= 0 ){
throw new IllegalArgumentException("addend1 is <= 0");
}
else if( addend2 <= 0 ){
throw new IllegalArgumentException("addend2 is <= 0");
}
return addend1 + addend2;
}
In either case, you need to check to make sure that the caller is using your API appropriately. But in the second case, you require it (implicitly). The soft Exceptions will still be thrown if the user didn't read the javadoc, but:
You don't need to document it.
You don't need to test for it (depending upon how aggresive your
unit testing strategy is).
You don't require the caller to handle three use cases.
The ground-level point is that Exceptions should not be used as return codes, largely because you've complicated not only YOUR API, but the caller's API as well.
Doing the right thing comes at a cost, of course. The cost is that everyone needs to understand that they need to read and follow the documentation. Hopefully that is the case anyway.
How about performance? While load testing a .NET web app we topped out at 100 simulated users per web server until we fixed a commonly-occuring exception and that number increased to 500 users.
I think that you can use Exceptions for flow control. There is, however, a flipside of this technique. Creating Exceptions is a costly thing, because they have to create a stack trace. So if you want to use Exceptions more often than for just signalling an exceptional situation you have to make sure that building the stack traces doesn't negatively influence your performance.
The best way to cut down the cost of creating exceptions is to override the fillInStackTrace() method like this:
public Throwable fillInStackTrace() { return this; }
Such an exception will have no stacktraces filled in.
Here are best practices I described in my blog post:
Throw an exception to state an unexpected situation in your software.
Use return values for input validation.
If you know how to deal with exceptions a library throws, catch them at the lowest level possible.
If you have an unexpected exception, discard current operation completely. Don’t pretend you know how to deal with them.
I don't really see how you're controlling program flow in the code you cited. You'll never see another exception besides the ArgumentOutOfRange exception. (So your second catch clause will never be hit). All you're doing is using an extremely costly throw to mimic an if statement.
Also you aren't performing the more sinister of operations where you just throw an exception purely for it to be caught somewhere else to perform flow control. You're actually handling an exceptional case.
Apart from the reasons stated, one reason not to use exceptions for flow control is that it can greatly complicate the debugging process.
For example, when I'm trying to track down a bug in VS I'll typically turn on "break on all exceptions". If you're using exceptions for flow control then I'm going to be breaking in the debugger on a regular basis and will have to keep ignoring these non-exceptional exceptions until I get to the real problem. This is likely to drive someone mad!!
Lets assume you have a method that does some calculations. There are many input parameters it has to validate, then to return a number greater then 0.
Using return values to signal validation error, it's simple: if method returned a number lesser then 0, an error occured. How to tell then which parameter didn't validate?
I remember from my C days a lot of functions returned error codes like this:
-1 - x lesser then MinX
-2 - x greater then MaxX
-3 - y lesser then MinY
etc.
Is it really less readable then throwing and catching an exception?
Because the code is hard to read, you may have troubles debugging it, you will introduce new bugs when fixing bugs after a long time, it is more expensive in terms of resources and time, and it annoys you if you are debugging your code and the debugger halts on the occurence of every exception ;)
If you are using exception handlers for control flow, you are being too general and lazy. As someone else mentioned, you know something happened if you are handling processing in the handler, but what exactly? Essentially you are using the exception for an else statement, if you are using it for control flow.
If you don't know what possible state could occur, then you can use an exception handler for unexpected states, for example when you have to use a third-party library, or you have to catch everything in the UI to show a nice error message and log the exception.
However, if you do know what might go wrong, and you don't put an if statement or something to check for it, then you are just being lazy. Allowing the exception handler to be the catch-all for stuff you know could happen is lazy, and it will come back to haunt you later, because you will be trying to fix a situation in your exception handler based on a possibly false assumption.
If you put logic in your exception handler to determine what exactly happened, then you would be quite stupid for not putting that logic inside the try block.
Exception handlers are the last resort, for when you run out of ideas/ways to stop something from going wrong, or things are beyond your ability to control. Like, the server is down and times out and you can't prevent that exception from being thrown.
Finally, having all the checks done up front shows what you know or expect will occur and makes it explicit. Code should be clear in intent. What would you rather read?
You can use a hammer's claw to turn a screw, just like you can use exceptions for control flow. That doesn't mean it is the intended usage of the feature. The if statement expresses conditions, whose intended usage is controlling flow.
If you are using a feature in an unintended way while choosing to not use the feature designed for that purpose, there will be an associated cost. In this case, clarity and performance suffer for no real added value. What does using exceptions buy you over the widely-accepted if statement?
Said another way: just because you can doesn't mean you should.
As others have mentioned numerously, the principle of least astonishment will forbid that you use exceptions excessively for control flow only purposes. On the other hand, no rule is 100% correct, and there are always those cases where an exception is "just the right tool" - much like goto itself, by the way, which ships in the form of break and continue in languages like Java, which are often the perfect way to jump out of heavily nested loops, which aren't always avoidable.
The following blog post explains a rather complex but also rather interesting use-case for a non-local ControlFlowException:
http://blog.jooq.org/2013/04/28/rare-uses-of-a-controlflowexception
It explains how inside of jOOQ (a SQL abstraction library for Java), such exceptions are occasionally used to abort the SQL rendering process early when some "rare" condition is met.
Examples of such conditions are:
Too many bind values are encountered. Some databases do not support arbitrary numbers of bind values in their SQL statements (SQLite: 999, Ingres 10.1.0: 1024, Sybase ASE 15.5: 2000, SQL Server 2008: 2100). In those cases, jOOQ aborts the SQL rendering phase and re-renders the SQL statement with inlined bind values. Example:
// Pseudo-code attaching a "handler" that will
// abort query rendering once the maximum number
// of bind values was exceeded:
context.attachBindValueCounter();
String sql;
try {
// In most cases, this will succeed:
sql = query.render();
}
catch (ReRenderWithInlinedVariables e) {
sql = query.renderWithInlinedBindValues();
}
If we explicitly extracted the bind values from the query AST to count them every time, we'd waste valuable CPU cycles for those 99.9% of the queries that don't suffer from this problem.
Some logic is available only indirectly via an API that we want to execute only "partially". The UpdatableRecord.store() method generates an INSERT or UPDATE statement, depending on the Record's internal flags. From the "outside", we don't know what kind of logic is contained in store() (e.g. optimistic locking, event listener handling, etc.) so we don't want to repeat that logic when we store several records in a batch statement, where we'd like to have store() only generate the SQL statement, not actually execute it. Example:
// Pseudo-code attaching a "handler" that will
// prevent query execution and throw exceptions
// instead:
context.attachQueryCollector();
// Collect the SQL for every store operation
for (int i = 0; i < records.length; i++) {
try {
records[i].store();
}
// The attached handler will result in this
// exception being thrown rather than actually
// storing records to the database
catch (QueryCollectorException e) {
// The exception is thrown after the rendered
// SQL statement is available
queries.add(e.query());
}
}
If we had externalised the store() logic into "re-usable" API that can be customised to optionally not execute the SQL, we'd be looking into creating a rather hard to maintain, hardly re-usable API.
Conclusion
In essence, our usage of these non-local gotos is just along the lines of what [Mason Wheeler][5] said in his answer:
"I just encountered a situation that I cannot deal with properly at this point, because I don't have enough context to handle it, but the routine that called me (or something further up the call stack) ought to know how to handle it."
Both usages of ControlFlowExceptions were rather easy to implement compared to their alternatives, allowing us to reuse a wide range of logic without refactoring it out of the relevant internals.
But the feeling of this being a bit of a surprise to future maintainers remains. The code feels rather delicate and while it was the right choice in this case, we'd always prefer not to use exceptions for local control flow, where it is easy to avoid using ordinary branching through if - else.
Typically there is nothing wrong, per se, with handling an exception at a low level. An exception IS a valid message that provides a lot of detail for why an operation cannot be performed. And if you can handle it, you ought to.
In general if you know there is a high probability of failure that you can check for... you should do the check... i.e. if(obj != null) obj.method()
In your case, i'm not familiar enough with the C# library to know if date time has an easy way to check whether a timestamp is out of bounds. If it does, just call if(.isvalid(ts))
otherwise your code is basically fine.
So, basically it comes down to whichever way creates cleaner code... if the operation to guard against an expected exception is more complex than just handling the exception; than you have my permission to handle the exception instead of creating complex guards everywhere.
You might be interested in having a look at Common Lisp's condition system which is a sort of generalization of exceptions done right. Because you can unwind the stack or not in a controlled way, you get "restarts" as well, which are extremely handy.
This doesn't have anything much to do with best practices in other languages, but it shows you what can be done with some design thought in (roughly) the direction you are thinking of.
Of course there are still performance considerations if you're bouncing up and down the stack like a yo-yo, but it's a much more general idea than "oh crap, lets bail" kind of approach that most catch/throw exception systems embody.
I don't think there is anything wrong with using Exceptions for flow-control. Exceptions are somewhat similar to continuations and in statically typed languages, Exceptions are more powerful than continuations, so, if you need continuations but your language doesn't have them, you can use Exceptions to implement them.
Well, actually, if you need continuations and your language doesn't have them, you chose the wrong language and you should rather be using a different one. But sometimes you don't have a choice: client-side web programming is the prime example – there's just no way to get around JavaScript.
An example: Microsoft Volta is a project to allow writing web applications in straight-forward .NET, and let the framework take care of figuring out which bits need to run where. One consequence of this is that Volta needs to be able to compile CIL to JavaScript, so that you can run code on the client. However, there is a problem: .NET has multithreading, JavaScript doesn't. So, Volta implements continuations in JavaScript using JavaScript Exceptions, then implements .NET Threads using those continuations. That way, Volta applications that use threads can be compiled to run in an unmodified browser – no Silverlight needed.
But you won't always know what happens in the Method/s that you call. You won't know exactly where the exception was thrown. Without examining the exception object in greater detail....
I feel that there is nothing wrong with your example. On the contrary, it would be a sin to ignore the exception thrown by the called function.
In the JVM, throwing an exception is not that expensive, only creating the exception with new xyzException(...), because the latter involves a stack walk. So if you have some exceptions created in advance, you may throw them many times without costs. Of course, this way you can't pass data along with the exception, but I think that is a bad thing to do anyway.
There are a few general mechanisms via which a language could allow for a method to exit without returning a value and unwind to the next "catch" block:
Have the method examine the stack frame to determine the call site, and use the metadata for the call site to find either information about a try block within the calling method, or the location where the calling method stored the address of its caller; in the latter situation, examine metadata for the caller's caller to determine in the same fashion as the immediate caller, repeating until one finds a try block or the stack is empty. This approach adds very little overhead to the no-exception case (it does preclude some optimizations) but is expensive when an exception occurs.
Have the method return a "hidden" flag which distinguishes a normal return from an exception, and have the caller check that flag and branch to an "exception" routine if it's set. This routine adds 1-2 instructions to the no-exception case, but relatively little overhead when an exception occurs.
Have the caller place exception-handling information or code at a fixed address relative to the stacked return address. For example, with the ARM, instead of using the instruction "BL subroutine", one could use the sequence:
adr lr,next_instr
b subroutine
b handle_exception
next_instr:
To exit normally, the subroutine would simply do bx lr or pop {pc}; in case of an abnormal exit, the subroutine would either subtract 4 from LR before performing the return or use sub lr,#4,pc (depending upon the ARM variation, execution mode, etc.) This approach will malfunction very badly if the caller is not designed to accommodate it.
A language or framework which uses checked exceptions might benefit from having those handled with a mechanism like #2 or #3 above, while unchecked exceptions are handled using #1. Although the implementation of checked exceptions in Java is rather nuisancesome, they would not be a bad concept if there were a means by which a call site could say, essentially, "This method is declared as throwing XX, but I don't expect it ever to do so; if it does, rethrow as an "unchecked" exception. In a framework where checked exceptions were handled in such fashion, they could be an effective means of flow control for things like parsing methods which in some contexts may have a high likelihood of failure, but where failure should return fundamentally different information than success. I'm unaware of any frameworks that use such a pattern, however. Instead, the more common pattern is to use the first approach above (minimal cost for the no-exception case, but high cost when exceptions are thrown) for all exceptions.
One aesthetic reason:
A try always comes with a catch, whereas an if doesn't have to come with an else.
if (PerformCheckSucceeded())
DoSomething();
With try/catch, it becomes much more verbose.
try
{
PerformCheckSucceeded();
DoSomething();
}
catch
{
}
That's 6 lines of code too many.
A lot of times when reading source code I see something like this:
public void Foo(Bar bar)
{
if (bar == null) return;
bar.DoSomething();
}
I do not like this, but I appear to be in the wrong as this form of defensive programming is considered good. Is it though? For example, why is bar null to begin with? Isn't doing checks like this akin to applying a bandage to a problem rather than solving the real solution? Not only does it complicate functions with additional lines of code but it also prevents the programmer from seeing potential bugs.
Here's another example:
public void Foo(int x)
{
int clientX = Math.Max(x, 0); // Ensures x is never negative
}
Others look at that and see defensive programming but I see future bugs when a programmer accidentally passes a negative value and the program suddenly breaks and no one knows why because this little bit of logic swallowed the potentially revealing exception.
Now, please do not confuse checking if user input is valid versus what I am asking here. Obviously user input should be checked. What I am asking only pertains to code that does not interact with the user or his or her input.
this int clientX = Math.Max(x, 0); is NOT defensive programming - it is masquerading potential problems!
Defensive programming would be
if ( x < 0 )
throw new Exception ( "whatever" ); // or return false or...
and defensive programming is absolutely recommended... you never know how this code will be called in the future so you make sure that it handles anything appropriately i.e. things it is unable to handle must be filtered out as early as possible and the caller must be "notified" (for example by a meaningful exception)...
You check for nulls because attempting to have a null object perform an operation will trigger an exception. "Nothing" cannot do "something." You code like this because you can never know 100% of the time what state your application will be in.
That being said, there are good and bad ways of coding against invalid states, and those examples you gave aren't exactly "good" ways, although it's hard to say when taken out of context.
A lot of time you might be building a component that will be used by different applications with input being supplied by different programmers with different coding styles, some may not perform thorough validation on data passed in to your component/method so defensive programming in this situation would be a good thing to catch this, regardless of what the user of the component does.
PS: one thing though, usually you would not just return from the method as you showed above, you would throw an appropriate Exception, maybe an InvalidArgumentException or something like that.
Probably you see this more often:
public void Foo(Bar bar)
{
if (bar == null) throw new ArgumentNullException("bar");
bar.DoSomething();
}
This way, if someone did supply a null value as parameter (maybe as a result of some other method), you don't see a NullReferenceException from "somewhere" in your code, but an exception that states the problem more clearly.
Simply returning on invalid input is akin to a silent try/catch in my opinion.
I still validate data coming into my functions from other pieces of code, but always throw an appropriate exception when I encounter invalid input.
Something like,
int clientX = Math.Max(x, 0)
could have really bad effects in some cases, just assume if you get x negative because of fault in some other place of the program, this would cause error to propagate. I would rather suggest you log and to throw an exception (some special type specific to business logic) when undesirable situation occurs.
Consider the following method signature:
public static bool TryGetPolls(out List<Poll> polls, out string errorMessage)
This method performs the following:
accesses the database to generate a list of Poll objects.
returns true if it was success and errorMessage will be an empty string
returns false if it was not successful and errorMessage will contain an exception message.
Is this good style?
Update:
Lets say i do use the following method signature:
public static List<Poll> GetPolls()
and in that method, it doesn't catch any exceptions (so i depend the caller to catch exceptions). How do i dispose and close all the objects that is in the scope of that method? As soon as an exception is thrown, the code that closes and disposes objects in the method is no longer reachable.
That method is trying to do three different things:
Retrieve and return a list of polls
Return a boolean value indicating success
Return an error message
That's pretty messy from a design standpoint.
A better approach would be to declare simply:
public static List<Poll> GetPolls()
Then let this method throw an Exception if anything goes wrong.
This is definitely not an idiomatic way of writing C#, which would also mean that it probably isn't a good style either.
When you have a TryGetPolls method then it means you want the results if the operation succeeds, and if it doesn't then you don't care why it doesn't succeed.
When you have simply a GetPolls method then it means you always want the results, and if it doesn't succeed then you want to know why in the form of an Exception.
Mixing the two is somewhere in between, which will be unusual for most people. So I would say either don't return the error message, or throw an Exception on failure, but don't use this odd hybrid approach.
So your method signatures should probably be either:
IList<Poll> GetPolls();
or
bool TryGetPolls(out IList<Poll> polls);
(Note that I'm returning an IList<Poll> rather than a List<Poll> in either case too, as it's also good practice to program to an abstraction rather than an implementation.)
I believe
public static bool TryGetPolls(out List<Poll> polls)
would be more appropriate. If the method is a TryGet then my initial assumption would be there is reason to expect it to fail, and onus is on the caller to determine what to do next. If they caller is not handling the error, or wants error information, I would expect them to call a corresponding Get method.
As a general rule, I would say no.
The reason I say no is actually not because you're performing a TryGetX and returning a bool with an out parameter. I think it's bad style because you're also returning an error string.
The Try should only ignore one specific, commonly-encountered error. Other problems may still throw an exception with the appropriate exception message. Remember that the goal of a Try method like this is to avoid the overhead of a thrown exception when you expect a particular, single sort of failure to happen more frequently than not.
Instead, what you're looking for is a pair of methods:
public static bool TryGetPolls( out List<Poll> polls );
public static List<Poll> GetPolls();
This way the user can do what's appropriate and GetPolls can be implemented in terms of TryGetPolls. I'm assuming that your staticness makes sense in context.
Consider returning:
an empty collection
null
Multiple out parameters, to me, is a code smell. The method should do ONE THING only.
Consider raising and handling error messages with:
throw new Exception("Something bad happened");
//OR
throw new SomethingBadHappenedException();
No, from my point of view this is very bad style. I would write it like this:
public static List<Poll> GetPolls();
If the call fails, throw an exception and put the error message in the exception. That's what exceptions are for and your code will become much cleaner, more readable and easier to maintain.
Not really - I can see a number of problems with this.
First of all, the method sounds like you'd normally expect it to succeed; errors (cannot connect to database, cannot access the polls table etc) would be rare. In this case, it is much more reasonable to use exceptions to report errors. The Try... pattern is for cases where you often expect the call to "fail" - e.g. when parsing a string to an integer, chances are good that the string is user input that may be invalid, so you need to have a fast way to handle this - hence TryParse. This isn't the case here.
Second, you report errors as a bool value indicating presence or absence of error, and a string message. How would the caller distinguish between various errors then? He certainly can't match on error message text - that is an implementation detail that is subject to change, and can be localized. And there might be a world of difference between something like "Cannot connect to database" (maybe just open the database connection settings dialog in this case and let the user edit it?) and "Connected to database, but it says 'Access Denied'". Your API gives no good way to distinguish between those.
To sum it up: use exceptions rather than bool + out string to report messages. Once you do it, you can just use List<Poll> as a return value, with no need for out argument. And, of course, rename the method to GetPolls, since Try... is reserved for bool+out pattern.
The guidelines say to try to avoid ref and out parameters if they are not absolutely required, because they make the API harder to use (no more chaining of methods, the developer has to declare all the variables before calling the method)
Also returning error codes or messages is not a best practice, the best practice is to use exceptions and exception handling for error reporting, else errors become to easy to ignore and there's more work passing the error info around, while at the same time losing valuable information like stacktrace or inner exceptions.
A better way to declare the method is like this.
public static List<Poll> GetPolls() ...
and for error reporting use exception handling
try
{
var pols = GetPols();
...
} catch (DbException ex) {
... // handle exception providing info to the user or logging it.
}
It depends on what the error message is. For instance, if processing couldn't continue because the database connection wasn't available, etc., then you should throw an exception as other people have mentioned.
However, it may be that you just want to return "meta" information about the attempt, in which case you just need a way to return more than one piece of information from a single method call. In that case, I suggest making a PollResponse class that contains two properties: List < Poll > Polls, and string ErrorMessage. Then have your method return a PollResponse object:
class PollResponse
{
public List<Poll> Polls { get; }
public string MetaInformation { get; }
}
Depends on if an error is a common occurance or if it us truly an exception.
If errors are gunuinely rare and bad then you might want to consider having the method just return the list of polls and throw an exception if an error occurs.
If an error is something that is realtively common part of normal operations, as like an error coverting a string to an integer in the int.TryParse method, the method you created would be more appropriate.
I'm guessing the former is probably the best case for you.
It depends on how frequently the method will fail. In general, errors in .Net should be communicated with an Exception. The case where that rule doesn't hold is when the error condidition is frequent, and the performance impact of throwing and exception is too high.
For Database type work I think an Exception is best.
I'd restate it like this.
public static List<Poll> GetPolls()
{
...
}
It should probably be throwing an exception (the errorMessage) if it fails to retrieve the polls, plus this allows for method chaining which is less cumbersome than dealing with out parameters.
If you run FxCop, you'll want to change List to IList to keep it happy.
I think its fine. I would prefer though:
enum FailureReasons {}
public static IEnumerable<Poll> TryGetPolls(out FailureReasons reason)
So the error strings don't live in the data-access code...
C# Methods should really only do one thing. You're trying to do three things with that method. I would do as others have suggested and throw an exception if there is an error. Another option would be to create extension methods for your List object.
e.g. in a public static class:
public static List<Poll> Fill( this List<Poll> polls) {
// code to retrieve polls
}
Then, to call this, you would do something like:
List<Poll> polls = new List<Poll>().Fill();
if(polls != null)
{
// no errors occur
}
edit: i just made this up. you may or may not need the new operator in List<Poll>().Fill()
Please state your assumptions, constraints, desires/goals, and reasoning; we're having to guess and/or read your mind to know what your intentions are.
assuming that you want your function to
create the polls list object
suppress all exceptions
indicate success with a boolean
and provide an optional error message on failure
then the above signature is fine (though swallowing all possible exceptions is not a good practice).
As a general coding style, it has some potential problems, as others have mentioned.
There is also this pattern, as seen in many Win32 functions.
public static bool GetPolls(out List<Poll> polls)
if(!PollStuff.GetPolls(out myPolls))
string errorMessage = PollStuff.GetLastError();
But IMO it's horrible.
I would go for something exception based unless this method has to run 65times per second in a 3d game physics engine or someting.
Did I miss something here? The question asker seems to want to know how to clean up resources if the method fails.
public static IList<Poll> GetPolls()
{
try
{
}
finally
{
// check that the connection happened before exception was thrown
// dispose if necessary
// the exception will still be presented to the caller
// and the program has been set back into a stable state
}
}
On a design side note, I'd consider pushing this method into a repository class so you have some sort of context with which to understand the method. The entire application, presumably, is not responsible for storing and getting Polls: that should be the responsibility of a data store.
I'm working on some code that uses a pattern in its business and data tiers that uses events to signal errors e.g.
resource = AllocateLotsOfMemory();
if (SomeCondition())
{
OnOddError(new OddErrorEventArgs(resource.StatusProperty));
resource.FreeLotsOfMemory();
return;
}
This looked superficially rather odd, especially as the code that calls this needs to hook into the events (there are four or five different ones!).
The developer tells me that this way they can refer to the properties of the allocated resource in the error handling code, and that responsibility for cleaning up after the error is kept by this tier.
Which makes some kind of sense.
The alternative might be something like
resource = AllocateLotsOfMemory();
if (SomeCondition())
{
BigObject temporary = resource.StatusProperty;
resource.FreeLotsOfMemory();
throw new OddException(temporary);
}
My questions are:
As this "BigObject" is freed when the exception object is released, do we need this pattern?
Has anyone else experience of this pattern? If so, what pitfalls did you find? What advantages are there?
Thanks!
It seems odd to me too. There are a few advantages - such as allowing multiple "handlers" but the semantics are significantly different to normal error handling. In particular, the fact that it doesn't automatically get propagated up the stack concerns me - unless the error handlers themselves throw an exception, the logic is going to keep going as if everything was still okay when it should probably be aborting the current operation.
Another way of thinking about this: suppose the method is meant to return a value, but you've detected an error early. What value do you return? Exceptions communicate the fact that there is no appropriate value to return...
This looks really odd to me, firstly IDisposable is your friend, use it.
If you are dealing with errors and exceptional situations you should be using exceptions, not events, as its much simpler to grasp, debug and code.
So it should be
using(var resource = AllocateLotsOfMemory())
{
if(something_bad_happened)
{
throw new SomeThingBadException();
}
}
If you think in terms of "Errors" and "Warnings", I've had lots of luck when reserving events for the "Warning" category and Exceptions for the "Errors" category.
The rationale here is that events are optional. No one is holding a gun to your head forcing you to handle them. That's probably okay for warnings, but when you have genuine errors you want to make sure they are taken a little more seriously. Exceptions must be handled, or they'll bubble up and create a nasty message for the user.
With regards to your Big Object question: you definitely don't be passing big objects around, but that doesn't mean you can't pass references to big objects around. There's a lot of power in the ability to do that.
As an addendum, there's nothing stopping from from raising an event in addition to the exception, but again: if you have a genuine error you want something to force the client developer to handle it.
Take a look at this post by Udi Dahan. Its an elegant approach for dispatching domain events. The previous poster is correct in saying that you should not be using an event mechanism to recover from fatal errors, but it is a very useful pattern for notification in loosely coupled systems:
public class DomainEventStorage<ActionType>
{
public List<ActionType> Actions
{
get
{
var k = string.Format("Domain.Event.DomainEvent.{0}.{1}",
GetType().Name,
GetType().GetGenericArguments()[0]);
if (Local.Data[k] == null)
Local.Data[k] = new List<ActionType>();
return (List<ActionType>) Local.Data[k];
}
}
public IDisposable Register(ActionType callback)
{
Actions.Add(callback);
return new DomainEventRegistrationRemover(() => Actions.Remove(callback)
);
}
}
public class DomainEvent<T1> : IDomainEvent where T1 : class
{
private readonly DomainEventStorage<Action<T1>> _impl = new DomainEventStorage<Action<T1>>();
internal List<Action<T1>> Actions { get { return _impl.Actions; } }
public IDisposable Register(Action<T1> callback)
{
return _impl.Register(callback);
}
public void Raise(T1 args)
{
foreach (var action in Actions)
{
action.Invoke(args);
}
}
}
And to consume:
var fail = false;
using(var ev = DomainErrors.SomethingHappened.Register(c => fail = true)
{
//Do something with your domain here
}
1) is it needed? no pattern is absolutely necessary
2) Windows Workflow Foundation does this with all the results from the Workflow Instances running inside the hosted runtime. Just remember that exceptions can happen when trying to raise that event, and you might want to do your cleanup code on a Dispose or a finally block depending on the situation to ensure it runs.
To be honest, events signaling errors strikes me as scary.
There's a disagreement between camps around returning status codes and throwing exceptions. To simplify (greatly) : The status code camp says that throwing exceptions places detecting and handling the error too far from the code causing the error. The exception throwing cap says that users forget to check status codes and exceptions enforce error handling.
Errors as events seems like the worst of both approaches. The error cleanup is completely separate from the code causing the error, and notification of error is completely voluntary. Ouch.
To me, if the method did not fulfill it's implicit or explicit contract (it didn't do what it was supposed to do), an exception is the apropriate response. Throwing the information you need in the exception seems reasonable in this case.
The first snippet should probably be
resource = AllocateLotsOfMemory();
if (SomeCondition())
{
try
{
OnOddError(new OddErrorEventArgs(resource.StatusProperty));
return;
}
finally
{
resource.FreeLotsOfMemory();
}
}
otherwise you won't free your resources when the event handler throws an exception.
As Mike Brown said, the second snippet also has a problem if resource.FreeLotsOfMemory() messes with the contents of resource.StatusProperty instead of setting it to null.
We have a base Error object and ErrorEvent that we use with the command pattern in our framework to handle non-critical errors (e.g. validation errors). Like exceptions, people can listen for the base ErrorEvent or a more specific ErrorEvent.
Also there's a significant difference between your two snippets.
if resource.FreeLotsOfMemory() clears out the StatusProperty value rather than just setting it to null, your temporary variable will be holding an invalid object when OddException is created and thrown.
The rule of thumb is that Exceptions should only be thrown in non-recoverable situations. I really wish C# supported a Throws clause that's the only thing I really miss from Java.
Another major problem with this approach are concurrency concerns.
With traditional error handling, locks will be released as control moves up the call stack to the error handler in a controlled manner. In this scheme, all locks will still be held when the event is invoked. Any blocking that occurs within the error handler (and you might expect some if there's logging) would be a potential source of deadlocks.