17

We have some code that archives data from a Microsoft Access database into a MS SQL Server database. Assuming we have a data reader already populated from the Access table and we are adding a parameter to a SqlCommand in preparation for the insert, we have a typecast that is failing. Here is the code:

oSqlServerDbCmd_ForInsert.Parameters.AddWithValue("@Duration",
     (int) oReader["Duration"]);

The field from the oReader is actually an Access Integer, which is a short in C#. If we cast to a short here there is no problem. However, if we cast to an int the code throws an InvalidCastException. I may be misreading this from the MSDN documentation:

"There is a predefined implicit conversion from short to int, long, float, double, or decimal."

...but it sounds like this should work (my reasoning being, if an implicit conversion is defined why would an explicit typecast not work?). I realize the cast is not even necessary because AddWithValue accepts an object, so we have actually removed the cast from our code, but I would love to see an explanation as to why this cast was failing just in case we run into something like this in the future.

A. Wilson
  • 688
  • 1
  • 6
  • 15
  • 1
    Good article from Eric Lippert on this http://blogs.msdn.com/b/ericlippert/archive/2009/03/19/representation-and-identity.aspx – Bryan Crosby Mar 16 '12 at 17:32
  • This is not an answer to your question, but it seems like your `@Duration` parameter should have a numeric data type, in which case you would not want to use a string value in the `AddWithValue` call. – phoog Mar 16 '12 at 19:00
  • @phoog I edited the code to remove that conversion as it is a distraction from what this question really ended up being about. The short answer is that the string conversion was in the code when we inherited it. Since it was working until we changed the data type in the source DB we'd had no cause to investigate the code. Once it was broken and we dug in we saw that the string conversion was unnecessary (although not problematic, believe it or not). – A. Wilson Mar 16 '12 at 19:56

2 Answers2

20

What you have in your hands is an instance of unboxing. Specifically when unboxing, you can only unbox to the type of the value that was originally boxed; if that type is A and you are unboxing to B, it does not matter if an implicit conversion from A to B exists (the unboxing will still fail).

See Eric Lippert's classic blog post on the subject for an involved explanation.

Jon
  • 428,835
  • 81
  • 738
  • 806
7

You have to cast to the very specific type since you are unboxing - the problem is that oReader["Duration"] returns an object instance:

short myShort = 42;
object o = myShort;
int myInt = (int)o; //fails

It will succeed if you cast back to short first, then to int:

(int) (short) oReader["Duration"]
BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
  • Thanks for the feedback, +1...you both answered my question so I'm going to have to go with first mover. – A. Wilson Mar 16 '12 at 17:38