Just looking for an explanation on this - the question pretty much explains it all but here's an bit extra:
//this line works OK
int i = Convert.ToInt32(dt.Rows[x]["SmallintColumnName"]);
//this line errors out
int j = (int)dt.Rows[x]["SmallintColumnName"];
I find this strange but I guess there's a valid argument on why this is like it is.
Thanks.
EDIT: Hi @Damien_The_Unbeliever - it is an InvalidCastException - Specified cast is not valid. I guess I need to read up on boxing and unboxing. I assumed that both would work. Now I have just tried:
int k = (Int32)r_dtAttribute.Rows[x]["CultureId"];
this also fails with the same InvalidCastException - so can anyone tell me what the actual difference is between
//fails
int k = (Int32)r_dtAttribute.Rows[x]["CultureId"];
and
//works
int i = Convert.ToInt32(dt.Rows[x]["SmallintColumnName"]);
What does the Convert.ToInt32 function do that just casting with (Int32) doesn't do?
Thanks
dt.Rows[x]["SmallintColumnName"]
is going to return anobject
. What the database returned has actually been translated (by ADO.Net) into anInt16
1, but since the return value of the expression isobject
, the value has been boxed.I linked in a comment to the article on Boxing and Unboxing. Your expression:
Is an attempt to unbox a value from an
object
. But the rules of boxing and unboxing say that you can only unbox exactly the same type that was boxed (except some weird rules to do with enums and their underlying types, IIRC). But since we know that what we have is a boxedInt16
, you're going to get anInvalidCastException
.What you could do is:
or even just:
Where we first unbox the
Int16
value and then explicitly (first example) or implicitly (second) cast theInt16
to anInt32
. It's slightly unfortunate that casting and unboxing look exactly the same.Convert.ToInt32(object)
is a whole different beast and supports all kinds of conversions. What it actually does is to cast the argument to theIConvertible
interface (whichInt16
supports) and then calls theToInt32
method on theInt16
. That, in turn, turns around and callsConvert.ToInt32(Int16)
, having switched back from being a boxedInt16
to just being a plainInt16
, which finally gets implicitly converted into anInt32
. Magic.1 I've tried, but I think failed, to be consistent throughout the answer in the type names I use. But be aware that
short
andInt16
are exactly the same type.int
andInt32
are also the same types. So switching your attempt from(int)
to(Int32)
didn't actually cause any change in the compiled code.