This project is read-only.

Support Multi-Catch

Topics: C# Language Design
Jul 27, 2014 at 8:26 PM
C# should support multi-catch:
try {
 ...
}
catch (StackOverflowException | OutOfMemoryException | ThreadAbortException) {
 throw; //let critical exceptions through (the BCL does this)
}
catch (Exception ex) {
 throw new WrappedException(ex); //or log it or handle it. whatever.
}
Inspiration taken from Java (http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html). There isn't a lot in Java that is better than C# but this is one of those few points.

The C# team should scan the Java language improvements that have been added or are under consideration. What's good should be added.

There isn't a lot to be learned (and in fact I'd recommend Java to just clone C# features because they have trouble getting it right on their own - see lambdas) but still there are a few things to be inspired by.
Jul 27, 2014 at 9:07 PM
Exception filters actually work better for this, because you avoid even the need for a rethrow:
catch (Exception ex) if (!(ex is OutOfMemoryException))
{
    throw new WrappedException(ex);
}
Note that in .Net you can't catch most of those exceptions anyway...
Jul 27, 2014 at 9:10 PM
Good point. Maybe there are other use cases than the one shown, though. Wanted to make sure you are aware of this possible feature. Thanks for delivering such a great language!
Jul 27, 2014 at 9:13 PM
We have considered it, but at the moment, I can't think of anything worth adding the complexity that isn't covered by exception filters.
Jul 28, 2014 at 5:19 PM
Pilchie wrote:
We have considered it, but at the moment, I can't think of anything worth adding the complexity that isn't covered by exception filters.
There are many cases where semantically-correct handling of exceptions would require filters, but the lack of filters in C# was, from what I understand, a deliberate design decision rather than an omission, probably predicated on the fact that .C# might--at least in theory--be used to develop code for runtimes which don't share the .NET two-pass exception model. Unless the maintainers of C# have a change of heart, I do not foresee general-purpose exception filters becoming available in C#. Consequently, I would expect that the most likely way to by which C# could come to support behaviors that are required for semantic correctness would be to have it incorporate features which would use exception filters behind the scenes, but whose behavior would not be defined in such terms. The two biggest ones I'd like to see would be
  1. Allow a finally block to know what exception occurred, without having to catch the exception. While it should be rare for code to resolve exceptions, it should be quite common for code to react to them. As a simple example, if code throws an unexpected exception in the middle of a multi-part update to an object, the object should be expressly invalidated. If the object ends up being abandoned (as would often, though not always, happen during stack unwinding), the fact that it may have been corrupted would be completely harmless. If the object ends up being used despite the corruption, such usage should trigger an exception, and it would be helpful for that exception to include information about what caused the object to be invalidated in the first place. Note that fault blocks are less than ideal for two reasons:

    a. They provide no mechanism by which the object can capture potentially useful information about the earlier exception, nor any mechanism by which cleanup code can throw an exception without destroying all trace of the earlier exception [in case of severe cleanup problems, the cleanup exception may be more relevant to the underlying code, but the original exception may contain more information which would be relevant to a human trying to troubleshoot it].

    b. Cleanup may require a mixture of code which should only be executed for a normal exit, code which should only be executed for an exception, and code which should execute in either case. If the natural ordering of cleanup operations intersperse the different types of code, having one set of code with if tests for the conditional would be more natural than having separate code paths that duplicate the code common to both.
  2. Allow code to test whether an exception object meets certain criteria while having the catch variable be of a more general type. Even if criteria are not allowed to call for the execution of arbitrary code, they could still include constraints which would not presently be allowable with catch variables. As a simple example, if exceptions meeting some criterion implement a common interface, it may be helpful to only catch exceptions which implement that interface. Existing exceptions don't currently support such interfaces, but code which wishes to be extensible could add support in catch statements, e.g.

    catch(Exception ex where ex is (SqlFormatException | AcmeDatabaseFormatException | IDatabaseFormatException))
Although the semantics above may only be accurately achieved in .NET using exception filters, they would not expose the internal workings of such filters to user code. Although it would be necessary when targeting .NET to capture an exception object and/or inspect its type in detail to determine whether to handle an exception before nested finally blocks execute (something that can only be done with filters), user code wouldn't care whether the semantics were provided using filters or some other entirely different mechanism which may be present in a different framework.

Personally, I think having finally(Exception ex) (and a corresponding variation of IDisposable) is more important, since many more exceptions should be acted upon than resolved, but for those cases where one really does expect to resolve an exception, being able to limit the exceptions caught to the ones which can be resolved is also important.
Jul 28, 2014 at 5:21 PM
@supercat: We've already added exception filters to C# 6.0. Try it out in the Roslyn preview, or VS "14" CTPs.
Marked as answer by TomasMatousek on 8/6/2014 at 12:02 AM