Note: I am very happy to tell you that exception filters are now in the C# 6.0 language.
This is a thought experiment, I'm interested in your opinion: Does it make sense to you? Do you know whether something similar has already been proposed for the C# programming language? I wouldn't even know where to send such a proposal...
The idea is introducing syntax elements to catch an Exception only if it fulfills a certain condition.
One use case example is when working with COM Interop: Everything always throws a COMException
. The actual distinguishing error code is contained in its message.
So what about (proposal 1):
try
{
...
}
catch (COMException ex where ex.Message.Contains("0x800706BA"))
{
// RPC server unavailable
}
catch (COMException ex where ex.Message.Contains("0x80010001"))
{
// Call rejected by callee
}
which translates to:
try
{
...
}
catch (COMException ex)
{
if (ex.Message.Contains("0x800706BA"))
{
// RPC server unavailable
}
else if (ex.Message.Contains("0x80010001"))
{
// Call rejected by callee
}
else
{
throw;
}
}
Similar cases are: SoapException
, XmlException
...
Another scenario is when exceptions are wrapped as inner exceptions within a general exception, and the catching logic should depend on the inner exception.
Say we have an API that wraps exceptions like this: catch (NumberFormatException ex) { throw new BusinessException(ex) }
.
What about (proposal 2A):
try
{
...
}
catch (inner NumberFormatException nfex)
{
...
}
which translates to:
catch (Exception ex where ex.InnerException is NumberFormatException)
{
NumberFormatException nfex = ex.InnerException;
...
}
or (2B):
catch (BusinessException bex inner NumberFormatException nfex)
{
...
}
which translates to:
catch (BusinessException bex where bex.InnerException is NumberFormatException)
{
NumberFormatException nfex = bex.InnerException;
...
}
In this case (originally from Java) it could look like (2C):
catch (RemoteAccessException raex inner inner MyException mex)
{
...
}
According to the try-catch C# Reference for Visual Studio 2015 RC this is now implemented:
Catch (ArgumentException e) when (e.ParamName == "…")
{
}
VB.Net has this feature of exception filter as shown below
Catch ex As COMException When ex.ErrorCode = 0x800706BA
So this is supported by the CLR but the feature is not exposed in C#
Supposedly F# has this feature as well but I don't know much about F# to show example.
Exceptions and types are tightly related. If you want to distinguish between two separate kinds of exceptions, you should make two exception types. In your example, you would have a Com800706BAException and a Com80010001Exception.
Now, this is not always possible or feasible, for example if the underlying system uses error codes instead of exceptions. In that case, your method may be helpful. However, this language feature would easily be misused. For example, you could do error handling like this, which is not type-safe:
catch (Exception e where e.Message = "The foo barfed up the bar")
If you want to check the inner exception of an exception, you are doing the error handling on the wrong level. The idea is that a method throws a generalized exception to abstract the caller from the inner working of the method. If you depend on some inner exception, you are tightly coupled to the implementation of the method. This is bad.
Either a separate, generalized exception should be thrown, or the error handling should be moved inside the method.
Why bake something into the language that is trivial to do anyway?
Proposal 1 is easily addressed with a targetted switch statement inside the catch - that way you can deal with the COM exceptions that you want and just rethrow anything you don't want to deal with.
The problem with Proposal 2 is that the exception stack could be arbitrarily deep, and could (or will) contain:
multiple nested instances of the same type of exception - which one should your query syntax deal with?
different exceptions which derive from the same base exception* - if your query syntax specifies one of the lower level base exceptions then that could match a whole bunch of higher level exceptions in the stack, which one(s) are you looking to process?
Most of the time when you are iterating the exception stack you won't be interested in retrieving the exception that is halfway down the stack, instead you will walk the exception stack and get the very first one for logging purposes. The rest of the time you only care about the last (outer) exception. I personally cannot recall a time where i had a need to programmatically catch/handle an exception that was buried somewhere in the middle of the stack, it has always been first, last, or all of them.
*disregarding the fact that all exceptions derive from System.Exception - i was meaning more along the lines of MyBaseException which all your custom exceptions derive from.
I think its pretty tricky and confusing:
What if your exception condition throws an exception as well? Where and how should that new exception be handled?
Since c# 7.0 this kind of stuff already supported. Here is full reference. Here is code snippet.
try
{
SomeOperationThatThrowsException();
}
catch(TheFilteredException ex ) when (ex.ErrorCode==123)
{
DoSomethingWhenExceptionThrown();
}
I'm not sure I like it that much. First off, it sounded like a really neat idea, but then I came to think, that if add syntactic sugar for this kind of thing, people will likely abuse exceptions when a status code is more appropriate.
As a few people have already pointed out, this is already in VB, however you could easily do something similar in C#:
catch (Exception ex)
{
if (ex.Message.Contains("Yikes!"))
{
// Do your thing
}
...
else
{
throw;
}
}
So, it's really just syntactic sugar.
The thing about exceptions is that (as often discussed on this site) they violate the sequential structure of your program, by potentially skipping a lot of code and popping the stack when you really didn't want that. This is why I don't think they are good for anything but very exceptional conditions, and if you really can somehow handle these conditions, it should be somewhat of a pain (try{}catch{if(..)} etc.), so that people wont be likely to use exceptions for more than these exceptional conditions.
User contributions licensed under CC BY-SA 3.0