Привет, у меня есть DataRow, извлеченный из DataTable из DataSet. Я обращаюсь к столбцу, который определен в SQL как тип данных с плавающей запятой. Я пытаюсь присвоить это значение локальной переменной (тип данных C# float), но получаю InvalidCastExecption
DataRow exercise = _exerciseDataSet.Exercise.FindByExerciseID(65);
_AccelLimit = (float)exercise["DefaultAccelLimit"];
Теперь, играя с этим, я заставил его работать, но это не имело никакого смысла и казалось неправильным.
_AccelLimit = (float)(double)exercise["DefaultAccelLimit"];
Может ли кто-нибудь объяснить, что мне здесь не хватает?





В соответствии с документация для SQLDbType, SQL-число с плавающей запятой является двойным.
Я согласен с комментариями Алена Мэй, но пока не понимаю, почему. Я видел случаи, когда .net double будет представлять числа, которые нарушают SQL с плавающей точкой. Примеры включают бесконечные значения и некоторые отрицательные показатели, приближающиеся к нулю. Я подозреваю, что MS оптимизирована для эффективности хранения.
@RaoulRubin: См. Документация MSDN для TSQL с плавающей запятой. Они никогда не упоминают соответствие IEEE и заявляют, что оно следует некоему неназванному стандарту ISO. Быстрый поиск дает ISO / IEC 10967, который заявляет, что он совместим с IEEE 754, но не гарантирует полной реализации.
Поплавок в SQL - это Двойной в CLR (C# / VB). На MSDN есть таблица типов данных SQL с эквивалентами CLR.
Они похожи, но, конечно, не эквивалентны. Double поддерживает значения + Infinity, -Infinity и NaN - в соответствии со спецификацией IEEE, но SQL с плавающей точкой определенно не поддерживает. и будет вызывать ошибки переполнения. Надеюсь, MSDN добавит это на свои информационные страницы.
В порядке. Так каков твой ответ?
Число с плавающей запятой в Microsoft SQL Server эквивалентно Double в C#. Причина этого в том, что число с плавающей запятой может приближаться только к десятичному числу, точность числа с плавающей запятой определяет, насколько точно это число приблизительно является десятичным числом. Тип Double представляет собой 64-разрядное число с плавающей запятой двойной точности со значениями в диапазоне от отрицательного 1,79769313486232e308 до положительного 1,79769313486232e308, а также положительного или отрицательного нуля, PositiveInfinity, NegativeInfinity и Not-a-Number (NaN).
И обычно вы никогда не захотите использовать float в SQL Server (или реальном), если вы планируете выполнять математические вычисления с данными, поскольку это неточный тип данных, и это приведет к ошибкам вычислений. Вместо этого используйте десятичный тип данных, если вам нужна точность.
Это нормально для большинства математических и инженерных расчетов. Теперь вычисления финансовая и бухгалтерская, конечно, другие.
Я думаю, что здесь был дан ответ на главный вопрос, но я чувствую себя обязанным добавить кое-что для раздела вопроса, в котором говорится, что это работает.
_AccelLimit = (float)(double)exercise["DefaultAccelLimit"];
Причина, по которой это «работает», и причина, по которой это «кажется неправильным», заключается в том, что вы понижаете двойное значение до float вторым приведением (слева), поэтому вы теряете точность и эффективно сообщаете компилятору, что он можно усечь возвращаемое значение.
На словах в этой строке говорится ... Получить объект (в данном случае он содержит двойник) Превратите объект в двойной (теряя всю обертку объекта) Превратите двойник в поплавок (теряя всю точность двойника)
например Если значение, скажем, 0,0124022806089461 и вы сделаете это, тогда значение AccelLimit будет 0,01240228
поскольку это степень того, что float в C# может получить от значения double. Это опасно, и я почти уверен, что это тоже усечение, а не округление, но кто-то может захотеть подтвердить это, поскольку я не уверен.
Причина, по которой это «кажется неправильным», заключается в том, что C# использует один и тот же синтаксис для распаковка и для Кастинг, которые являются двумя очень разными вещами. exercise["DefaultAccelLimit"] содержит двойное значение, заключенное в рамку как объект. (double) требуется для распаковать объекта обратно в двойной. (float) перед этим, затем бросает двойное до значения с плавающей запятой. C# не допускает упаковки и преобразования в одной операции, поэтому необходимо распаковать, а затем преобразовать.
То же самое верно, даже если слепок неразрушающий. Если бы поплавок был упакован как объект, который вы хотели преобразовать в двойное, вы бы сделали это так: (double)(float)object_var.
Они похожи, но, конечно, не эквивалентны. Double поддерживает значения + Infinity, -Infinity и NaN - в соответствии со спецификацией IEEE, но SQL с плавающей точкой определенно не поддерживает. и будет вызывать ошибки переполнения.