I have a number of methods doing next:
var result = command.ExecuteScalar() as Int32?; if(result.HasValue) { return result.Value; } else { throw new Exception(); // just an example, in my code I throw my own exception }
I wish I could use operator ??
like this:
return command.ExecuteScalar() as Int32? ?? throw new Exception();
but it generates a compilation error.
Is it possible to rewrite my code or there is only one way to do that?
You can't throw an exception in a ternary clause. Both options must return a value, which throw new Exception(); doesn't satisfy.
Using the Throws keyword Throws is a keyword used to indicate that this method could throw this type of exception. The caller has to handle the exception using a try-catch block or propagate the exception. We can throw either checked or unchecked exceptions.
Throwing exceptions from C++ constructors Since C++ constructors do not have a return type, it is not possible to use return codes. Therefore, the best practice is for constructors to throw an exception to signal failure. The throw statement can be used to throw an C++ exception and exit the constructor code.
"throw "and "throw new" Exception() In the above case, throws the original exception but resets the stack trace , destroying all stack trace information until your catch block. This means that, it excludes stack information from the point where you called "Throw ex" .
For C# 7
In C# 7, throw
becomes an expression, so it's fine to use exactly the code described in the question.
For C# 6 and earlier
You can't do that directly in C# 6 and earlier - the second operand of ?? needs to be an expression, not a throw statement.
There are a few alternatives if you're really just trying to find an option which is concise:
You could write:
public static T ThrowException<T>() { throw new Exception(); // Could pass this in }
And then:
return command.ExecuteScalar() as int? ?? ThrowException<int?>();
I really don't recommend that you do that though... it's pretty horrible and unidiomatic.
How about an extension method:
public static T ThrowIfNull(this T value) { if (value == null) { throw new Exception(); // Use a better exception of course } return value; }
Then:
return (command.ExecuteScalar() as int?).ThrowIfNull();
Yet another alternative (again an extension method):
public static T? CastOrThrow<T>(this object x) where T : struct { T? ret = x as T?; if (ret == null) { throw new Exception(); // Again, get a better exception } return ret; }
Call with:
return command.ExecuteScalar().CastOrThrow<int>();
It's somewhat ugly because you can't specify int?
as the type argument...
As has been said, you can't do this with the ?? operator (well, not without some contortions that don't seem to fit with your aim of making this cleaner).
When I see this pattern emerging I immediately think of Enforcements. Originally from the C++ world they transfer to C# pretty well, although are arguably less important most of the time.
The idea is that you take something of the form:
if( condition ) { throw Exception; }
and converts it to:
Enforce<Exception>( condition );
(you can further simplify by defaulting the exception type).
Taking it further you can write a set of Nunit-style methods for different condition checks, e.g.;
Enforce<Exception>.NotNull( obj ); Enforce<Exception>.Equal( actual, expected ); Enforce<Exception>.NotEqual( actual, expected );
etc.
Or, better still by providing an expectation lamba:
Enforce<Exception>( actual, expectation );
What's really neat is that, once you've done that, you can return the the actual param and enforce inline:
return Enforce( command.ExecuteScalar() as Int32?, (o) => o.HasValue ).Value;
... and this seems to be the closest to what you're after.
I've knocked up an implementation of this before. There's a couple of little niggles, like how you generically create an exception object that takes arguments - some choices there (I chose reflection at the time, but passing a factory in as an extra parameter may be even better). But in general it's all pretty straightforward and can really clean up a lot of code.
It's on my list of things to do to knock up an open source implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With