Exceptional Edge Cases

It’s stated as conventional wisdom that in .NET a throw expression must throw an object of a type that is System.Exception, or derived from System.Exception.  Here’s the language from the C# specification (Section 8.9.5):

A throw statement with an expression throws the value produced by evaluating the expression. The expression must denote a value of the class type System.Exception, of a class type that derives from System.Exception, or of a type parameter type that has System.Exception (or a subclass thereof) as its effective base class.

Let’s play with the edge cases.  What will this do:

throw default(NotImplementedException);

 

The expression is typed correctly (it is a NotImplementedException.) But, it’s null. The answer to this is in the next sentence of the C# Specification:

If evaluation of the expression produces null, a System.NullReferenceException is thrown instead.

That means this is also legal:

throw null;

It will throw a NullReferenceException, as specified  above.

Now, let’s see what happens if we work with a type that can be converted to an exception:

struct Exceptional
{     public static implicit operator Exception(Exceptional e)     {         return null;     }
}

 

An Exceptional can be converted (implicitly) to an Exception. But this results in a compile time error:

 

throw new Exceptional();

 

The compiler reports that the type thrown must be derived from System.Exception. So, let’s rewrite the code so that it is:

Exception e = new Exceptional();
throw e;

 

The first line creates an Exceptional struct. Assigning it to a variable of type Exception invokes the implicit conversion. Now, it is of type Exception, and can be thrown.

Finally, what about this expression:

dynamic d = new Exceptional();
throw d;

 

In most places in the language, where an expression must evaluate to a specific type, an expression of type dynamic is allowed.

Here we have the joy of edge cases. The spec (as I’ve quoted above) doesn’t speak to this case. Where the spec is silent, sometimes developers interpret them differently. The classic compiler (pre-Roslyn) accepts throwing an expression that is dynamic. The Roslyn (VS 2015) compiler does not. I expect this may change, and the spec may get updated to explicitly state the behavior.

Created: 9/24/2015 2:24:33 PM

Current Projects

I create content for .NET Core. My work appears in the .NET Core documentation site. I'm primarily responsible for the section that will help you learn C#.

All of these projects are Open Source (using the Creative Commons license for content, and the MIT license for code). If you would like to contribute, visit our GitHub Repository. Or, if you have questions, comments, or ideas for improvement, please create an issue for us.

I'm also the president of Humanitarian Toolbox. We build Open Source software that supports Humanitarian Disaster Relief efforts. We'd appreciate any help you can give to our projects. Look at our GitHub home page to see a list of our current projects. See what interests you, and dive in.

Or, if you have a group of volunteers, talk to us about hosting a codeathon event.