Qual è il miglior tipo di dati da utilizzare per denaro in C #?


426

Qual è il miglior tipo di dati da utilizzare per denaro in C #?


4
Potresti trovare utili le risposte a questo post .
ntombela,

Ecco una mappatura per tutti i tipi di dati: docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
JohnLBevan,

Inoltre, se si utilizza le annotazioni di dati, includere using System.ComponentModel.DataAnnotations;... [DataType(DataType.Currency)] msdn.microsoft.com/en-us/library/...
JohnLBevan

Risposte:


422

Come è descritto in decimale come:

La parola chiave decimale indica un tipo di dati a 128 bit. Rispetto ai tipi a virgola mobile, il tipo decimale ha più precisione e un intervallo più piccolo, il che lo rende appropriato per i calcoli finanziari e monetari .

È possibile utilizzare un decimale come segue:

decimal myMoney = 300.5m;

41
Dovresti spiegare cosa è importante riguardo a quel link. Una risposta dovrebbe essere abbastanza buona da sola, con un collegamento come riferimento o dettaglio aggiuntivo. Vedere stackoverflow.com/help/how-to-answer
TheRubberDuck

2
Quindi la risposta di lunghezza minima può contenere meno caratteri rispetto al commento di lunghezza minima - interessante! Non che io abbia un problema con la risposta concisa / concisa, specialmente quando è anche "profonda" in quanto si collega a ulteriori discussioni.
B. Clay Shannon,

3
Risposta incredibile, e non credo che abbia bisogno di ulteriori spiegazioni poiché risponde completamente alla domanda. Il collegamento alla documentazione MSDN è un vantaggio per quanto mi riguarda. Bravo!
Trnelson,

@Leee Treveil, com'è il denaro (9.0098) significa 4 personaggi dopo Point
SAR

114

System.Decimal

Il tipo di valore decimale rappresenta numeri decimali che vanno da 79.228.162.514.264.337.593.543.950.335 positivi a 79.228.162.514.264.337.593.543.950.335 negativi. Il tipo di valore decimale è appropriato per i calcoli finanziari che richiedono un numero elevato di cifre integrali e frazionarie significative e nessun errore di arrotondamento. Il tipo decimale non elimina la necessità di arrotondamento. Piuttosto, minimizza gli errori dovuti all'arrotondamento.

Vorrei sottolineare questa eccellente risposta di zneak sul perché il doppio non dovrebbe essere usato.


68

Utilizzare il modello Money da Patterns of Enterprise Application Architecture ; specifica l'importo come decimale e la valuta come enum.


2
In realtà stavo per suggerire questo, ma faccio della Valuta una classe in modo da poter definire un tasso di cambio (in relazione a una "valuta di base", spesso il dollaro USA [che ho impostato per avere un tasso di cambio di 1,00]).
Thomas Owens,

5
Per i futuri visitatori di questa discussione (come me), ora c'è questo: nuget.org/packages/Money e spacca !
Korijn,

Mi chiedo se un tale tipo dovrebbe essere una struttura o una classe. Un decimale + un enum (int) lo rende 20 byte. I miei soldi sono ancora su Struct.
nawfal,

Quel Moneynuget ha un link github morto per il sito del progetto, quindi ... nessun documento?
George Mauer,

Il problema è che se stai creando la tua implementazione, devi capire come perseverarla effettivamente. E l'ORM (EF) più popolare non ha alcun supporto per tipi di dati personalizzati. Quindi qualcuno si chiede di entrare davvero nel profondo delle erbacce a fare quello che dovrebbe essere una cosa abbastanza semplice.
George Mauer,

25

Decimale. Se scegli il doppio ti stai lasciando aperto agli errori di arrotondamento


8
@Jess doublepuò introdurre errori di arrotondamento perché il virgola mobile non può rappresentare esattamente tutti i numeri (es. 0.01 non ha una rappresentazione esatta in virgola mobile). Decimal, D'altra parte, non rappresentare i numeri esattamente . (Il trade-off Decimalha un intervallo inferiore rispetto al virgola mobile) Il virgola mobile può causare errori di arrotondamento * involontari * (ad esempio 0.01+0.01 != 0.02). Decimalpuò darti errori di arrotondamento, ma solo quando lo hai richiesto (ad es. Math.Round(0.01+0.02)restituisce zero)
Ian Boyd,

2
@IanBoyd: il valore "$ 1,57" può essere rappresentato con precisione (doppio) 157. Se uno usa doublee applica con attenzione il ridimensionamento e l'arrotondamento specifico del dominio, se del caso, può essere perfettamente preciso. Se uno è sciatto nel proprio arrotondamento, decimalpuò produrre risultati semanticamente errati (ad esempio se si sommano più valori che dovrebbero essere arrotondati al penny più vicino, ma in realtà non li circonda prima). L'unica cosa positiva decimalè che il ridimensionamento è integrato.
supercat

1
@supercat, riguardo a questo commento "se si sommano più valori che dovrebbero essere arrotondati al penny più vicino, ma in realtà non li circonda prima", non vedo come un float risolva questo. Si tratta di un errore dell'utente e non ha nulla a che fare con i decimali IMHO. Capisco il punto ma sento che è stato mal riposto, soprattutto perché IanBoyd ha specificato che ... se lo chiedi.
visto il


13

Concordi con il modello monetario: la gestione delle valute è troppo ingombrante quando si utilizzano i decimali.

Se crei una classe di valuta, puoi quindi inserire tutta la logica relativa al denaro, incluso un metodo ToString () corretto, un maggiore controllo dei valori di analisi e un migliore controllo delle divisioni.

Inoltre, con una classe Currency, non vi è alcuna possibilità di mescolare involontariamente denaro con altri dati.


10

Un'altra opzione (specialmente se stai lanciando la tua classe) è usare un int o un int64 e designare le quattro cifre inferiori (o forse anche 2) come "diritto del punto decimale". Quindi "ai bordi" avrai bisogno di "* 10000" mentre entri e di "/ 10000" all'uscita. Questo è il meccanismo di archiviazione utilizzato da SQL Server di Microsoft, vedi http://msdn.microsoft.com/en-au/library/ms179882.aspx

La cosa bella è che tutta la tua somma può essere fatta usando l'aritmetica intera (veloce).


7

Molte applicazioni con cui ho lavorato decimalrappresentano denaro. Ciò si basa sul presupposto che l'applicazione non riguarderà mai più di una valuta.

Questa ipotesi può essere basata su un'altra ipotesi, secondo cui l'applicazione non verrà mai utilizzata in altri paesi con valute diverse. Ho visto casi in cui ciò si è rivelato falso.

Ora questa ipotesi viene sfidata in un modo nuovo: le nuove valute come Bitcoin stanno diventando più comuni e non sono specifiche per nessun paese. Non è irrealistico che un'applicazione utilizzata in un solo paese possa ancora aver bisogno di supportare valute multiple.

Alcune persone diranno che la creazione o persino l'uso di un tipo solo per soldi è "doratura" o l'aggiunta di ulteriore complessità oltre i requisiti noti. Sono fortemente in disaccordo. Più un concetto ubiquitario è all'interno del tuo dominio, più è importante fare uno sforzo ragionevole per utilizzare l'astrazione corretta in anticipo. Se vuoi vedere la complessità, prova a lavorare in un'applicazione che usava decimale ora c'è una Currencyproprietà aggiuntiva accanto a ogni decimalproprietà.

Se usi l'astrazione sbagliata in anticipo, sostituirla in seguito sarà cento volte più impegnativa. Ciò significa che è possibile che vengano introdotti difetti nel codice esistente e la parte migliore è che tali difetti implicheranno probabilmente somme di denaro, transazioni con denaro o qualsiasi altra cosa con denaro.

E non è così difficile usare qualcosa di diverso dal decimale. Google "nuget money type" e vedrai che numerosi sviluppatori hanno creato tali astrazioni (incluso me.) È facile. È facile come usare DateTimeinvece di memorizzare una data in a string.


5

Crea la tua classe. Sembra strano, ma un tipo .Net non è adeguato per coprire valute diverse.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.