Search code examples
c#typesthrowcompile-timec#-7.0

What is the compile-time type of the "throw" expression in C# 7?


In C# 7 it is possible to raise an exception inside an expression:

int n = list != null ? list.Count : throw new NullReferenceException("list");

In this position, the throw expression can substitute an expression of any type.

Now I want to define a function that executes some action before raising an exception:

??? DoSomethingAndThrowException(Exception e)
{
    MessageBox.Show("Prepare for an exception!");
    throw e;
}

What would be the return type of such function, so that it can be used in the same places as the original throw expression:

int n = list != null ? list.Count : DoSomethingAndThrowException(new NullReferenceException("list"));

There's the option to declare it as a generic method:

T DoSomethingAndThrowException<T>(Exception e) {...}

But this seems cumbersome, as the generic type doesn't occur anywhere in the function body. Is this the only way to do it, or is there some type I don't know of, and which is assignable to any type (an "anti-object" type, so to speak)?


Solution

  • The type you're talking about is known as the bottom type, the subtype of all types, as opposed to the top type, the supertype of all types.

    As you noted, the top type in C# is called object*. On the other hand, C# does not have the bottom type (though there is a proposal to add it).

    Though there actually is one type that has implicit conversions to any other type: dynamic. This means that if you set the return type of DoSomethingAndThrowException to dynamic, your code would compile. But I don't think dynamic is a good choice here, because it's too infectious. For example, if you used var in your statement (var n = list != null ? list.Count : DoSomethingAndThrowException(new NullReferenceException("list"));), then the type of n would be dynamic, with all the baggage that brings.

    I think this means that your conclusion is correct: generics are your best option.

    * Technically, object is not the top type, because object is not the supertype of pointer types. But I think that's a distinction that doesn't matter much.