¿Cuál es el mejor tipo de datos para usar con dinero en C #?


426

¿Cuál es el mejor tipo de datos para usar con dinero en C #?


44
Puede encontrar útiles las respuestas de esta publicación .
ntombela

Aquí hay una asignación para todos los tipos de datos: docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
JohnLBevan

Además, si usa anotaciones de datos, incluya using System.ComponentModel.DataAnnotations;... [DataType(DataType.Currency)] msdn.microsoft.com/en-us/library/…
JohnLBevan

Respuestas:


422

Como se describe en decimal como:

La palabra clave decimal indica un tipo de datos de 128 bits. En comparación con los tipos de coma flotante, el tipo decimal tiene más precisión y un rango más pequeño, lo que lo hace apropiado para cálculos financieros y monetarios .

Puede usar un decimal de la siguiente manera:

decimal myMoney = 300.5m;

41
Deberías explicar qué pasa con ese enlace es importante. Una respuesta debería ser lo suficientemente buena por sí sola, con un enlace como referencia o detalle adicional. Ver stackoverflow.com/help/how-to-answer
TheRubberDuck

2
Por lo tanto, la respuesta de longitud mínima puede tener menos caracteres que el comentario de longitud mínima, ¡interesante! No es que tenga un problema con la respuesta concisa / concisa, especialmente cuando también es "profunda", ya que se vincula a una discusión más profunda.
B. Clay Shannon

3
Respuesta asombrosa, y no creo que necesite más explicaciones ya que responde completamente la pregunta. El enlace a la documentación de MSDN es una ventaja en lo que a mí respecta. ¡Bravo!
Trnelson

@Leee Treveil, cómo es el dinero (9.0098) significa 4 caracteres después del Punto
SAR

114

System.Decimal

El tipo de valor decimal representa números decimales que van desde 79,228,162,514,264,337,593,543,950,335 positivos hasta 79,228,162,514,264,337,593,543,950,335 negativos. El tipo de valor decimal es apropiado para cálculos financieros que requieren grandes cantidades de dígitos integrales y fraccionarios significativos y sin errores de redondeo. El tipo decimal no elimina la necesidad de redondeo. Más bien, minimiza los errores debidos al redondeo.

Me gustaría señalar esta excelente respuesta de zneak sobre por qué el doble no debe usarse.


68

Utilice el patrón Money de Patrones de arquitectura de aplicaciones empresariales ; especifique la cantidad como decimal y la moneda como una enumeración.


2
En realidad iba a sugerir esto, pero hago de la Moneda una clase para poder definir un tipo de cambio (en relación con una "moneda base", a menudo el dólar estadounidense [que establecí para tener un tipo de cambio de 1,00]).
Thomas Owens

55
Para los futuros visitantes de este hilo (como yo), ahora hay esto: nuget.org/packages/Money y ¡es genial !
Korijn

Preguntándose si ese tipo debería ser una estructura o clase. Un enum decimal + an (int) hace 20 bytes. Mi dinero todavía está en struct.
nawfal

Ese Moneynuget tiene un enlace github muerto para el sitio del proyecto, así que ... ¿no hay documentos?
George Mauer

El problema con esto es que si está creando su propia implementación, tiene que descubrir cómo persistirla realmente. Y el ORM (EF) más popular no tiene soporte para los tipos de datos personalizados. Por lo tanto, se le pide a alguien que se meta profundamente en la maleza para hacer lo que debería ser algo bastante sencillo.
George Mauer el

25

Decimal. Si elige el doble, se deja abierto a errores de redondeo


8
@Jess doublepuede introducir errores de redondeo porque el punto flotante no puede representar todos los números exactamente (por ejemplo, 0.01 no tiene representación exacta en punto flotante). Decimal, Por otro lado, no representar números con exactitud . (La compensación Decimaltiene un rango menor que el punto flotante) El punto flotante puede generar * errores de redondeo * inadvertidos * (p 0.01+0.01 != 0.02. Ej .). Decimalpuede darle errores de redondeo, pero solo cuando lo solicitó (por ejemplo, Math.Round(0.01+0.02)devuelve cero)
Ian Boyd

2
@IanBoyd: El valor "$ 1.57" se puede representar con precisión (doble) 157. Si uno usa doubley aplica cuidadosamente el escalado y el redondeo específico del dominio cuando sea apropiado, puede ser perfectamente preciso. Si uno es descuidado en el redondeo, decimalpuede producir resultados semánticamente incorrectos (por ejemplo, si se suman varios valores que se supone que se redondean al centavo más cercano, pero en realidad no los rodea primero). Lo único bueno decimales que la escala está integrada.
supercat

1
@supercat, con respecto a este comentario "si uno agrega múltiples valores que se supone que se redondean al centavo más cercano, pero en realidad no los rodea primero", no veo cómo un flotador resolvería esto. Es un error del usuario y no tiene nada que ver con decimales en mi humilde opinión. entiendo el punto, pero siento que se ha extraviado, principalmente porque IanBoyd lo especificó ... si lo pides.
sawe


13

De acuerdo con el patrón de dinero: el manejo de monedas es demasiado engorroso cuando usa decimales.

Si crea una clase de Moneda, puede colocar allí toda la lógica relacionada con el dinero, incluido un método ToString () correcto, un mayor control de los valores de análisis y un mejor control de las divisiones.

Además, con una clase de moneda, no hay posibilidad de mezclar dinero involuntariamente con otros datos.


10

Otra opción (especialmente si está rodando su propia clase) es usar un int o un int64, y designar los cuatro dígitos inferiores (o posiblemente incluso 2) como "a la derecha del punto decimal". Así que "en los bordes" necesitarás "* 10000" al entrar y "/ 10000" al salir. Este es el mecanismo de almacenamiento utilizado por el servidor SQL de Microsoft, consulte http://msdn.microsoft.com/en-au/library/ms179882.aspx

Lo bueno de esto es que toda su suma se puede hacer usando aritmética de enteros (rápidos).


7

La mayoría de las aplicaciones con las que he trabajado utilizan decimalpara representar dinero. Esto se basa en el supuesto de que la aplicación nunca tendrá que ver con más de una moneda.

Esta suposición puede basarse en otra suposición, que la aplicación nunca se utilizará en otros países con monedas diferentes. He visto casos donde eso resultó ser falso.

Ahora esa suposición está siendo desafiada de una nueva manera: nuevas monedas como Bitcoin se están volviendo más comunes, y no son específicas de ningún país. No es poco realista que una aplicación utilizada en un solo país todavía necesite admitir varias monedas.

Algunas personas dirán que crear o incluso usar un tipo solo por dinero es "chapado en oro" o agregar complejidad adicional más allá de los requisitos conocidos. Estoy totalmente en desacuerdo. Cuanto más ubicuo es un concepto dentro de su dominio, más importante es hacer un esfuerzo razonable para utilizar la abstracción correcta por adelantado. Si desea ver la complejidad, intente trabajar en una aplicación que solía usar decimaly ahora hay una Currencypropiedad adicional al lado de cada decimalpropiedad.

Si usa la abstracción incorrecta por adelantado, reemplazarla más tarde será cien veces más trabajo. Eso significa potencialmente introducir defectos en el código existente, y la mejor parte es que esos defectos probablemente involucrarán cantidades de dinero, transacciones con dinero o simplemente cualquier cosa con dinero.

Y no es tan difícil usar algo que no sea decimal. Google "nuget money type" y verá que numerosos desarrolladores han creado tales abstracciones (incluyéndome a mí). Es fácil. Es tan fácil como usar en DateTimelugar de almacenar una fecha en a string.


5

Crea tu propia clase. Esto parece extraño, pero un tipo .Net es inadecuado para cubrir diferentes monedas.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.