¿Por qué un flotador SQL es diferente de un flotador C #

Hola, tengo un DataRow sacado de una DataTable de un DataSet. Estoy accediendo a una columna que está definida en SQL como un tipo de datos flotante. Intento asignar ese valor a una variable local (tipo de datos flotante c #) pero obtengo un InvalidCastExecption

DataRow exercise = _exerciseDataSet.Exercise.FindByExerciseID(65); _AccelLimit = (float)exercise["DefaultAccelLimit"]; 

Ahora, jugando con esto, lo hice funcionar, pero no tenía sentido y no me pareció bien.

 _AccelLimit = (float)(double)exercise["DefaultAccelLimit"]; 

¿Alguien puede explicar lo que me falta aquí?

Un flotante SQL es un doble según la documentation de SQLDbType .

Un flotante en SQL es un doble en el CLR (C # / VB). Hay una tabla de types de datos SQL con los equivalentes de CLR en MSDN.

El flotador en Microsoft SQL Server es equivalente a un doble en C #. La razón para esto es que un número de coma flotante solo puede aproximarse a un número decimal, la precisión de un número de coma flotante determina con qué precisión ese número se aproxima a un número decimal. El tipo doble representa un número de coma flotante de 64 bits de doble precisión con valores que van desde 1.79769313486232e308 negativo a 1.79769313486232e308 positivo, así como cero positivo o negativo, afinidad positiva, indefinición negativa y no-número (NaN).

Y normalmente nunca querrá usar float en SQL Server (o real) si planea realizar cálculos matemáticos en los datos ya que es un tipo de datos inexacto e introducirá errores de cálculo. Use un tipo de datos decimal en su lugar si necesita precisión.

Creo que la pregunta principal ha sido respondida aquí, pero me siento obligado a agregar algo para la sección de la pregunta que dice que esto funciona.

_AccelLimit = (float) (double) exercise ["DefaultAccelLimit"];

La razón por la que esto "funciona" y la razón por la que "no se siente bien" es que estás degradando el doble a una carroza por el segundo elenco (el de la izquierda), así que estás perdiendo precisión y diciéndole al comstackdor que está bien para truncar el valor devuelto.

En palabras, esta línea dice … Obtener un object (que en este caso contiene un doble) Emitir el object en un doble (perder todo el ajuste del object) Emitir el doble en un flotante (perdiendo toda la precisión fina de un doble)

por ejemplo, si el valor es, por ejemplo, 0.0124022806089461 y usted hace lo anterior, entonces el valor de AccelLimit será 0.01240228

como ese es el scope de lo que puede get un flotador en c # del doble valor. Es algo peligroso de hacer y estoy bastante seguro de que es un truncamiento también en lugar de un networkingondeo, pero alguien puede querer confirmar esto ya que no estoy seguro.

La razón por la que "no se siente bien" es porque C # usa la misma syntax para desempaquetar y para emitir , que son dos cosas muy diferentes. exercise["DefaultAccelLimit"] contiene un valor doble, encuadrado como un object. (double) es necesario para volver a poner el object en un doble. El (float) al frente de eso arroja el doble a un valor flotante. C # no permite el boxeo y el casting en la misma operación, por lo que debes desempaquetar y luego lanzar.

Lo mismo es cierto incluso si el elenco no es destructivo. Si un flotador estaba encuadrado como un object que deseaba convertir en un doble, lo haría de la siguiente manera: (double)(float)object_var .