Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / All-Topics

Exceptional Edge Cases

5.00/5 (2 votes)
16 Dec 2015CPOL2 min read 3.9K  
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:

C#
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:

C#
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:

C#
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:

C#
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:

C#
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:

C#
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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)