Using null-coalescing as a replacement for try catch block
-
07-04-2021 - |
Domanda
How come I get an invalid cast exception when trying to set a NULL
value returned from the database inside Comments
which is of type Int32
.
I am trying to replace this:
try
{
objStreamItem.Comments = (Int32)sqlReader["Comments"];
if (objStreamItem.Comments > 0) {
listComments = Comment.GetAll(objStreamItem.Id);
}
}
catch (InvalidCastException)
{
// Execute if "Comments" returns NULL
listComments = null;
objStreamItem.Comments = 0;
}
With this:
Comments = ((Int32?)sqlReader["Comments"]) ?? 0
The two are in different contexts, but you should get the idea. Instead of using a try catch block I am trying to solve this in a more elegant way.
Thanks.
UPDATE
It is stored as a nullable integer in the database.
public int? Comments
{
get;
set;
}
I just want to thank everyone who answered or posted on this question, everything was very informative. thanks!
Soluzione
I suppose a ternary expression is the way to go here
objStreamItem.Comments = sqlReader["Comments"] is DBNull ? 0 : (Int32)sqlReader["Comments"] ;
You could also store the return value of sqlReader["Comments"]
in a variable first to shorten the expression
var comments = sqlReader["Comments"];
objStreamItem.Comments = comments is DBNull ? 0 : (Int32)comments;
Altri suggerimenti
Your SQL reader is returning DBNull
when the value is null; There's no conversion from DBNull
to int?
, and the null-coalescing operator doesn't recognize DBNull.Value
as something that needs to be coalesced.
EDIT 3
(Another problem with your original code: It will assume that "Comments" returned null if "Comments" is non-null but GetAll()
throws an InvalidCastException
.)
As hvd points out, you can use the as operator with nullable types:
objStreamItem.Comments = sqlReader["Comments"] as int?;
listComments = (objStreamItem.Comments ?? 0) > 0 ? Comment.GetAll(objStreamItem.ID) : null;
You could save yourself from all of this, however, if you simply defined Comment.GetAll()
to return an empty list or a null reference when the ID you pass to it has no comments.
The ??
operator checks for null
, but sqlReader["Comments"]
won't ever be null
. It will either be an Int32
, or a DBNull
. You can cast null
to Int32?
, but you cannot do so with DBNull.Value
. You can use sqlReader["Comments"] as Int32?
instead, which checks if the result can be converted to Int32
, and if not, assigns null
.
That statement tries to perform the cast before coalescing the values. You need to add parenthesis. Judging by your example above, it also looks like the field is an int
rather than an int?
:
Comments = (Int32)(sqlReader["Comments"] ?? 0);