Який найкращий тип даних використовувати для грошей у C #?


426

Який найкращий тип даних використовувати для грошей у C #?


4
Ви можете знайти відповіді з цієї публікації корисними.
ntombela

Ось картування для всіх типів даних: docs.microsoft.com/en-us/dotnet/framework/data/adonet/…
JohnLBevan

Крім того, якщо ви використовуєте примітки про дані, включіть using System.ComponentModel.DataAnnotations;... [DataType(DataType.Currency)] msdn.microsoft.com/en-us/library/…
JohnLBevan

Відповіді:


422

Як це описано в десятковій формі як:

Десяткове ключове слово вказує на 128-бітний тип даних. Порівняно з типами з плаваючою комою, десятковий тип має більшу точність та менший діапазон, що робить його відповідним для фінансових та грошових розрахунків.

Десятковий знак можна використовувати так:

decimal myMoney = 300.5m;

41
Ви повинні пояснити, що важливо для цього посилання. Відповідь має бути достатньо власною, із додатковою посиланням або деталізацією. Див stackoverflow.com/help/how-to-answer
TheRubberDuck

2
Тож відповідь мінімальної довжини може мати менше символів, ніж коментар мінімальної довжини - цікаво! Не те, що у мене є проблема з короткою / стислою відповіддю, особливо, коли вона також є "глибокою" в тому, що вона посилається на подальше обговорення.
Б. Клей Шеннон

3
Дивовижна відповідь, і я не думаю, що вона потребує подальшого пояснення, оскільки вона повністю відповідає на питання. Що стосується мене, посилання на документацію MSDN - це бонус. Браво!
trnelson

@Leee Treveil, як виглядають гроші (9.0098) означає 4 символи після пункту
SAR

114

Система.Decimal

Тип десяткового значення представляє десяткові числа в діапазоні від позитивних 79,228,162,514,264,337,593,543,950,335 до від’ємних 79,228,162,514,264,337,593,543,950,335. Тип десяткового значення підходить для фінансових розрахунків, що вимагають великої кількості значущих інтегральних і дробових цифр і відсутність помилок округлення. Тип Десяткова не виключає необхідності округлення. Швидше, це мінімізує помилки через округлення.

Я хотів би вказати на відмінну відповідь zneak про те, чому не слід використовувати подвійний.


68

Використовуйте шаблон грошей із шаблонів архітектури прикладних програм підприємства ; вкажіть суму як десяткову, а валюту - як перерахунок.


2
Я насправді збирався запропонувати це, але я ставлю Валюту класом, щоб я міг визначити обмінний курс (по відношенню до "базової валюти", часто долара США [для якого я встановив курс 1,00]).
Томас Оуенс

5
Для майбутніх відвідувачів цього потоку (як я) тепер є це: nuget.org/packages/Money, і воно гойдається!
Корінь

Цікаво, чи такий тип повинен бути структура чи клас. Десяткове значення + an (int) перерахунок складає 20 байт. Мої гроші все ще на структурі.
nawfal

Цей Moneyнут має мертве посилання github для сайту проекту, так що ... немає документів?
Джордж Мауер

Проблема в цьому полягає в тому, що якщо ви створюєте власну реалізацію, ви повинні з'ясувати, як насправді її зберегти. А найпопулярніший ORM (EF) взагалі не підтримує користувацькі типи даних. Тому хто - то попросив , щоб отримати дійсно глибоко в бур'янах , щоб робити те , що повинно бути досить простою річчю.
Джордж Мауер

25

Десяткові. Якщо ви обираєте подвійний, ви залишаєте себе відкритим для помилок округлення


8
@Jess doubleможе вводити помилки округлення, оскільки плаваюча точка не може точно представляти всі числа (наприклад, 0,01 не має точного подання у плаваючій точці). Decimal, З іншого боку, робить подання чисел точно . (Компроміс Decimalмає менший діапазон, ніж плаваюча точка) Плаваюча точка може надати вам * ненавмисні * помилки округлення (наприклад 0.01+0.01 != 0.02). Decimalможе надати помилки округлення, але лише тоді, коли ви просили про це (наприклад, Math.Round(0.01+0.02)повертає нуль)
Ian Boyd

2
@IanBoyd: Значення "1,57 $" можна точно представити (подвійне) 157. Якщо ви використовуєте doubleта ретельно застосовуєте масштабування та округлення домену, коли це доречно, це може бути абсолютно точно. Якщо хтось неохайний в округленні, це decimalможе призвести до семантично неправильних результатів (наприклад, якщо ви додаєте кілька значень, які повинні бути округлені до найближчої копійки, але насправді не спочатку навколо них). Єдине добре в тому decimal, що масштабування вбудовано.
supercat

1
@supercat, щодо цього коментаря, "якщо ви додасте кілька значень, які повинні бути округлені до найближчої копійки, але насправді не спочатку навколо них", я не бачу, як поплавок вирішить це. Це помилка користувача і не має нічого спільного з децималами IMHO. Я розумію, але я вважаю, що це було неправильно, головним чином тому, що IanBoyd вказав це ... якщо ви попросите цього.
sawe


13

Погодьтеся з моделлю грошей: обробка валют є занадто громіздкою, коли ви використовуєте десяткові дроби.

Якщо ви створюєте валютний клас, ви можете вкласти туди всю логіку, що стосується грошей, включаючи правильний метод ToString (), більше контролю над значеннями розбору та кращим контролем поділів.

Крім того, для класу Валюта немає шансів ненавмисно змішати гроші з іншими даними.


10

Іншим варіантом (особливо, якщо ви прокатуєте власний клас), є використання int або int64, і позначити чотири нижні цифри (або, можливо, навіть 2) як "праворуч від десяткової коми". Тож "по краях" вам знадобиться кілька "* 10000" на виході, а деякі "/ 10000" на виході. Це механізм зберігання даних, використовуваний SQL-сервером Microsoft, див. Http://msdn.microsoft.com/en-au/library/ms179882.aspx

Суть цього полягає в тому, що все ваше підсумовування можна зробити, використовуючи (швидку) цілу арифметику.


7

Більшість застосунків, з якими я працював, decimalпредставляв гроші. Це ґрунтується на припущенні, що заявка ніколи не стосуватиметься більше однієї валюти.

Це припущення може базуватися на іншому припущенні, що додаток ніколи не буде використовуватися в інших країнах з різними валютами. Я бачив випадки, коли це виявилося помилковим.

Тепер це припущення оскаржується по-новому: нові валюти, такі як біткойн, стають все більш поширеними, і вони не характерні для будь-якої країни. Нереально, що додатку, що використовується лише в одній країні, все ще може знадобитися підтримка кількох валют.

Деякі люди скажуть, що створення або навіть використання типу лише для грошей - це «позолочення» або додавання додаткової складності понад відомі вимоги. Я категорично не згоден. Чим більше всюдисуща концепція знаходиться у вашому домені, тим важливіше докласти розумних зусиль, щоб використовувати правильну абстракцію вперед. Якщо ви хочете побачити складність, спробуйте працювати в додатку, який раніше використовувався, decimalа тепер Currencyпоруч із кожною decimalвласністю є додаткова властивість.

Якщо ви використовуєте неправильну абстракцію на передній панелі, її заміна пізніше буде в сто разів більше роботи. Це означає, що потенційно можна ввести дефекти в існуючий код, і найкраще, що ці дефекти, ймовірно, включатимуть гроші, операції з грошима або просто що-небудь з грошима.

І не так складно використовувати щось інше, ніж десятковий. Google "нудний тип грошей", і ви побачите, що численні розробники створили такі абстракції (включаючи мене.) Це просто. Це так само просто, як використовувати DateTimeзамість зберігання дати в string.


5

Створіть свій власний клас. Це здається дивним, але тип .Net недостатній для покриття різних валют.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.