Почему я получаю арифметическое переполнение, когда :(Int64)(System.Data.SqlTypes.SqlInt16.MaxValue+1);

Что я упускаю из виду в приведенном ниже выражении? Разве тип Int64 не имеет большего диапазона, чем Int16?

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

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

32767 + 1 = 32768. А это намного(!) меньше, чем 9223372036854775807.

Так почему же я получаю арифметическое переполнение, когда использую

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

в Int64?

(Это как-то связано с реализацией оператора + в С# или...?)


person pencilCake    schedule 20.02.2014    source источник


Ответы (5)


SqlTypes.SqlInt16 — интересный тип. Он выглядит как short?, но на самом деле это структура. У него есть куча перегрузок операторов, которые заставляют его вести себя как число. Обратите внимание, как эта версия работает просто отлично:

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

В котором используется «обычный» оператор сложения, он никогда не может переполниться, поскольку в CLR на самом деле нет оператора сложения, который работает для short. Ближайший тип, который он поддерживает, — это Int32, который здесь не переполняется.

Но SqlInt16 был написан, чтобы поймать эту ошибку, он имеет перегрузку operator+(), он был явно написан для генерации этого исключения. Другими словами, он действительно реализует семантику 16-битного сложения и кричит, когда результат не помещается обратно в столбец таблицы dbase 16-битного целочисленного типа. Независимо от того, используете ли вы ключевые слова checked или unchecked в C#. Что хорошо, вы действительно хотите знать об этом, когда работаете с базой данных.

Вам нужно вызвать другой метод SqlInt16, оператор преобразования. Тот, который преобразует SqlInt16 в собственный целочисленный тип. Насмешливая разновидность выглядит так:

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

Но, конечно, имеет больше смысла напрямую приводить к Int64, SqlInt16 также имеет оператор преобразования для этого:

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

Остерегайтесь сомнительной семантики такого кода. Вы не можете привести столбец dbase. Мой первый фрагмент имеет больше смысла.

person Hans Passant    schedule 20.02.2014

Вы пытаетесь преобразовать результат SqlInt16.MaxValue+1 в Int64. Но SqlInt16.MaxValue это SqlInt16. Добавление +1 к этому вызовет переполнение еще до того, как вы его разыграете.


То, что вы хотите сделать, это сначала преобразовать SqlInt16.MaxValue в Int64, а затем добавить к нему 1:

Int64 value = (Int64)System.Data.SqlTypes.SqlInt16.MaxValue + 1;
person Dirk    schedule 20.02.2014

Сделайте это вместо этого, вы пытаетесь добавить 1 к максимальному значению System.Data.SqlTypes.SqlInt16

Int64 value = (Int64)(System.Data.SqlTypes.SqlInt16.MaxValue) +1;
person Josh Anderson    schedule 20.02.2014

Потому что (System.Data.SqlTypes.SqlInt16.MaxValue+1) это int16 - или пытается быть как минимум, что недопустимо.

Просто сначала приведите MaxValue к int64, а потом добавьте 1.

Просто для примера:

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

Наведите указатель мыши на знак + в своем коде, и вы увидите всплывающую подсказку, сообщающую вам, что это (разрешение перегрузки) переходит к «определяемому пользователем» оператору. Выберите «Перейти к определению» или F12 на этом символе +, и вы увидите подпись:

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

(документация)

Итак, теперь вы знаете, что правый операнд 1 неявно преобразуется в SqlInt16 (сначала неявно преобразуется из int в short с помощью правил C# для преобразования константных (литеральных) выражений, а затем преобразуется из short в SqlInt16 с помощью "определяемого пользователем" implicit operator) . Затем у нас есть два значения SqlInt16. operator выше принимает их и хочет вернуть третье значение SqlInt16, их сумму. Но это невозможно. Возникает исключение.

Так что мы никогда не доберемся до твоего гипса до Int64; проблема возникает раньше.

Чтобы исправить это, явно преобразуйте System.Data.SqlTypes.SqlInt16.MaxValue, например, в Int64 (он же long) или Int16 (он же short) перед добавлением (+).

Конечно, вы также можете использовать:

long value = short.MaxValue + 1;

потому что short.MaxValue имеет то же числовое значение, что и SqlInt16.MaxValue, но я не знаю, сможете ли вы использовать это в своем приложении.

person Jeppe Stig Nielsen    schedule 20.02.2014