views:

150

answers:

6

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)
{
    ...
}
A: 

Why don't you just check it in a switch statement?

Marcus Johansson
This does not answer the question. Therefore, this is not an answer but a comment. Please use the "add comment" link at the bottom of the question instead of the "Add answer" form.
Sjoerd
dotnet give a facility to catch lot's of known exception and unknown exception by using lot's exception so why we need switch rather then much switch
steven spielberg
+4  A: 

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.

Sjoerd
As you say, *this is not always possible*: Interop always throws `COMException`. I am the client of the Interop, not the programmer...
chiccodoro
+6  A: 

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.

Pratik
+1 Fantastic! Since VB.NET has this feature, I don't think it's a difficult work for the dev team to add this feature to C#.
Danny Chen
But then probably not an unknown request, and as others have said, it doesn't give you the power to do anything you can't currently do. To be blunt, it doesn't even simplify things much. As such, the cost of adding it (and the manhours or minutes to change the syntax is just a small portion of it, google for Eric Lippert and you'll probably find some of his lists of things that cost during a change) is probably too large for what basically amounts to different syntax to do what you can already do. So no, probably not difficult, but probably not going to be done either.
Lasse V. Karlsen
Syntactic sugar, this is not supported on CLR level.
leppie
Exception filters are powerful as the filter is evaluated before the catch block is executed. But this has surprising side effects if you are not careful. Basically the filter and the check inside a try block differs in a significant way for the order of evaluation. [see]( http://blogs.msdn.com/b/clrteam/archive/2009/08/25/the-good-and-the-bad-of-exception-filters.aspx)
Pratik
@leppie It definitely is supported at CLR and IL level. Both VB.Net and F# has it. Check a detailed explanation from the blog post referenced in my earlier comment on how exception handling works in two pass by CLR.
Pratik
@Pratik: Thanks! I never knew how to use that. Now I have an example from VB.NET. Looks quite interesting from initial investigation :)
leppie
@Pratik: You should include that link in your answer, e.g. [is supported by the CLR][1] [1]: http://blogs.msdn.com/b/clrteam/archive/2009/08/25/the-good-and-the-bad-of-exception-filters.aspx
chiccodoro
+2  A: 

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.

slugster
+1  A: 

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.

cwap
+2  A: 

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?

  • A try/catch around a catch block? meh..
  • Let other catch blocks handled that exception: StackOverflows yay :)
Arcturus