Why do I get Arithmetic overflow when :(Int64)(System.Data.SqlTypes.SqlInt16.MaxValue+1);

StackOverflow https://stackoverflow.com/questions/21903961

  •  14-10-2022
  •  | 
  •  

Pregunta

What do I overlook in the expression below? Does not Int64 type has larger range than Int16?

Int64 value = (Int64)(System.Data.SqlTypes.SqlInt16.MaxValue+1);

System.Data.SqlTypes.SqlInt16.MaxValue is 32767. Int64.MaxValue() is 9223372036854775807.

32767 + 1 = 32768. And that is much(!) lower than 9223372036854775807.

So why do I get Aritmethic Overflow when I cast

(Int64)(System.Data.SqlTypes.SqlInt16.MaxValue+1);

to Int64?

(Is it something to do with the implementation of + operator in C# or...?)

¿Fue útil?

Solución

SqlTypes.SqlInt16 is an interesting type. It looks like a short? but it is not, it is actually a struct. It has a bunch of operator overloads that makes it behave like a number. Do note how this version works just fine:

    Int64 value = (Int64)(short.MaxValue + 1);    // okay

Which uses the "normal" addition operator, it can never overflow since the CLR doesn't actually have a addition operator that works for short. The nearest type it supports is Int32, that doesn't overflow here.

But SqlInt16 was written to catch this mistake, it has an operator+() overload, it was explicitly written to generate this exception. In other words, it does implement the semantics of a 16-bit addition and yells when the result doesn't fit back into a dbase table column of a 16-bit integral type. Regardless whether you use the checked or unchecked keywords in C#. Which is a Good Thing, you really want to know about that when you work with a dbase.

You need to invoke another method of SqlInt16, a conversion operator. The one that converts SqlInt16 to a native integral type. The tongue-in-cheek variety looks like this:

   Int64 value = (Int64)((short)System.Data.SqlTypes.SqlInt16.MaxValue + 1);

But of course it makes more sense to cast to Int64 directly, SqlInt16 has a conversion operator for that one too:

   Int64 value = (Int64)System.Data.SqlTypes.SqlInt16.MaxValue + 1;

Do beware the iffy semantics of code like this. You can't cast a dbase column. My first snippet makes more sense.

Otros consejos

You are trying to cast the result ot SqlInt16.MaxValue+1 to an Int64. But SqlInt16.MaxValue is a SqlInt16. Adding +1 to that will overflow before you even cast it.


What you want to do is first cast the SqlInt16.MaxValue to Int64 and then add 1 to it:

Int64 value = (Int64)System.Data.SqlTypes.SqlInt16.MaxValue + 1;

Do this instead, you're trying to add 1 to the max value of System.Data.SqlTypes.SqlInt16

Int64 value = (Int64)(System.Data.SqlTypes.SqlInt16.MaxValue) +1;

Because (System.Data.SqlTypes.SqlInt16.MaxValue+1) is an int16 - or trying to be at least, which is invalid.

Just cast the MaxValue to int64 first, then add 1 afterwards.

Just to examplify this:

var x = (System.Data.SqlTypes.SqlInt16.MaxValue + 0);
var t = x.GetType(); // t will be System.Data.SqlTypes.SqlInt16

Hover your mouse over the + sign in your code, and you will get a tool tip popping up telling you it (overload resolution) goes to a "user-defined" operator. Choose "Go to definition" or F12 on that + character, and you will see the signature:

public static SqlInt16 operator +(SqlInt16 x, SqlInt16 y);

(documentation)

So you now know that the right-hand operand 1 is implicitly converted to SqlInt16 (first converted implicitly from int to short via C#'s rules for constant (literal) expression conversions, then converted from short to SqlInt16 via a "user-defined" implicit operator). Then we have two SqlInt16 values. The operator above takes them in and wants to return a third SqlInt16 value, their sum. But that is impossible. The exception arises.

So we never get to your cast to Int64; the problem occurs before that.

To fix it, explicitly convert System.Data.SqlTypes.SqlInt16.MaxValue to e.g. Int64 (a.k.a. long) or Int16 (a.k.a. short) before the addition (+).

Of course, you can also use:

long value = short.MaxValue + 1;

because short.MaxValue has the same numerical value as SqlInt16.MaxValue, but I don't know if you can use this in your application.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top