NumberFormatInfo.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676
  1. //
  2. // System.Globalization.NumberFormatInfo.cs
  3. //
  4. // Author:
  5. // Derek Holden ([email protected])
  6. // Bob Smith ([email protected])
  7. //
  8. // (C) Derek Holden
  9. // (C) Bob Smith http://www.thestuff.net
  10. //
  11. //
  12. // NumberFormatInfo. One can only assume it is the class gotten
  13. // back from a GetFormat() method from an IFormatProvider /
  14. // IFormattable implementer. There are some discrepencies with the
  15. // ECMA spec and the SDK docs, surprisingly. See my conversation
  16. // with myself on it at:
  17. // http://lists.ximian.com/archives/public/mono-list/2001-July/000794.html
  18. //
  19. // Other than that this is totally ECMA compliant.
  20. //
  21. namespace System.Globalization {
  22. [Serializable]
  23. public sealed class NumberFormatInfo : ICloneable, IFormatProvider {
  24. private bool readOnly;
  25. // Currency Related Format Info
  26. private int currencyDecimalDigits;
  27. private string currencyDecimalSeparator;
  28. private string currencyGroupSeparator;
  29. private int[] currencyGroupSizes;
  30. private int currencyNegativePattern;
  31. private int currencyPositivePattern;
  32. private string currencySymbol;
  33. private string naNSymbol;
  34. private string negativeInfinitySymbol;
  35. private string negativeSign;
  36. // Number Related Format Info
  37. private int numberDecimalDigits;
  38. private string numberDecimalSeparator;
  39. private string numberGroupSeparator;
  40. private int[] numberGroupSizes;
  41. private int numberNegativePattern;
  42. // Percent Related Format Info
  43. private int percentDecimalDigits;
  44. private string percentDecimalSeparator;
  45. private string percentGroupSeparator;
  46. private int[] percentGroupSizes;
  47. private int percentNegativePattern;
  48. private int percentPositivePattern;
  49. private string percentSymbol;
  50. private string perMilleSymbol;
  51. private string positiveInfinitySymbol;
  52. private string positiveSign;
  53. internal NumberFormatInfo (int lcid)
  54. {
  55. //FIXME: should add more LCID
  56. // CultureInfo uses this one also.
  57. if (lcid != 0x007F)
  58. lcid = 0x007F;
  59. switch (lcid){
  60. // The Invariant Culture Info ID.
  61. case 0x007f:
  62. readOnly = false;
  63. // Currency Related Format Info
  64. currencyDecimalDigits = 2;
  65. currencyDecimalSeparator = ".";
  66. currencyGroupSeparator = ",";
  67. currencyGroupSizes = new int[1] { 3 };
  68. currencyNegativePattern = 0;
  69. currencyPositivePattern = 0;
  70. currencySymbol = "$";
  71. naNSymbol = "NaN";
  72. negativeInfinitySymbol = "-Infinity";
  73. negativeSign = "-";
  74. // Number Related Format Info
  75. numberDecimalDigits = 2;
  76. numberDecimalSeparator = ".";
  77. numberGroupSeparator = ",";
  78. numberGroupSizes = new int[1] { 3 };
  79. numberNegativePattern = 1;
  80. // Percent Related Format Info
  81. percentDecimalDigits = 2;
  82. percentDecimalSeparator = ".";
  83. percentGroupSeparator = ",";
  84. percentGroupSizes = new int[1] { 3 };
  85. percentNegativePattern = 0;
  86. percentPositivePattern = 0;
  87. percentSymbol= "%";
  88. perMilleSymbol = "\u2030";
  89. positiveInfinitySymbol = "Infinity";
  90. positiveSign = "+";
  91. break;
  92. }
  93. }
  94. public NumberFormatInfo () : this (0x007f)
  95. {
  96. }
  97. // =========== Currency Format Properties =========== //
  98. public int CurrencyDecimalDigits {
  99. get {
  100. return currencyDecimalDigits;
  101. }
  102. set {
  103. if (value < 0 || value > 99)
  104. throw new ArgumentOutOfRangeException
  105. ("The value specified for the property is less than 0 or greater than 99");
  106. if (readOnly)
  107. throw new InvalidOperationException
  108. ("The current instance is read-only and a set operation was attempted");
  109. currencyDecimalDigits = value;
  110. }
  111. }
  112. public string CurrencyDecimalSeparator {
  113. get {
  114. return currencyDecimalSeparator;
  115. }
  116. set {
  117. if (value == null)
  118. throw new ArgumentNullException
  119. ("The value specified for the property is a null reference");
  120. if (readOnly)
  121. throw new InvalidOperationException
  122. ("The current instance is read-only and a set operation was attempted");
  123. currencyDecimalSeparator = value;
  124. }
  125. }
  126. public string CurrencyGroupSeparator {
  127. get {
  128. return currencyGroupSeparator;
  129. }
  130. set {
  131. if (value == null)
  132. throw new ArgumentNullException
  133. ("The value specified for the property is a null reference");
  134. if (readOnly)
  135. throw new InvalidOperationException
  136. ("The current instance is read-only and a set operation was attempted");
  137. currencyGroupSeparator = value;
  138. }
  139. }
  140. public int[] CurrencyGroupSizes {
  141. get {
  142. return currencyGroupSizes;
  143. }
  144. set {
  145. if (value == null || value.Length == 0)
  146. throw new ArgumentNullException
  147. ("The value specified for the property is a null reference");
  148. if (readOnly)
  149. throw new InvalidOperationException
  150. ("The current instance is read-only and a set operation was attempted");
  151. // All elements except last need to be in range 1 - 9, last can be 0.
  152. int last = value.Length - 1;
  153. for (int i = 0; i < last; i++)
  154. if (value[i] < 1 || value[i] > 9)
  155. throw new ArgumentOutOfRangeException
  156. ("One of the elements in the array specified is not between 1 and 9");
  157. if (value[last] < 0 || value[last] > 9)
  158. throw new ArgumentOutOfRangeException
  159. ("Last element in the array specified is not between 0 and 9");
  160. currencyGroupSizes = (int[]) value.Clone();
  161. }
  162. }
  163. public int CurrencyNegativePattern {
  164. get {
  165. // See ECMA NumberFormatInfo page 8
  166. return currencyNegativePattern;
  167. }
  168. set {
  169. if (value < 0 || value > 15)
  170. throw new ArgumentOutOfRangeException
  171. ("The value specified for the property is less than 0 or greater than 15");
  172. if (readOnly)
  173. throw new InvalidOperationException
  174. ("The current instance is read-only and a set operation was attempted");
  175. currencyNegativePattern = value;
  176. }
  177. }
  178. public int CurrencyPositivePattern {
  179. get {
  180. // See ECMA NumberFormatInfo page 11
  181. return currencyPositivePattern;
  182. }
  183. set {
  184. if (value < 0 || value > 3)
  185. throw new ArgumentOutOfRangeException
  186. ("The value specified for the property is less than 0 or greater than 3");
  187. if (readOnly)
  188. throw new InvalidOperationException
  189. ("The current instance is read-only and a set operation was attempted");
  190. currencyPositivePattern = value;
  191. }
  192. }
  193. public string CurrencySymbol {
  194. get {
  195. return currencySymbol;
  196. }
  197. set {
  198. if (value == null)
  199. throw new ArgumentNullException
  200. ("The value specified for the property is a null reference");
  201. if (readOnly)
  202. throw new InvalidOperationException
  203. ("The current instance is read-only and a set operation was attempted");
  204. currencySymbol = value;
  205. }
  206. }
  207. // =========== Static Read-Only Properties =========== //
  208. public static NumberFormatInfo CurrentInfo {
  209. get {
  210. // This should be culture specific
  211. NumberFormatInfo nfi = new NumberFormatInfo ();
  212. nfi.readOnly = true;
  213. return nfi;
  214. }
  215. }
  216. public static NumberFormatInfo InvariantInfo {
  217. get {
  218. // This uses invariant info, which is same as in the constructor
  219. NumberFormatInfo nfi = new NumberFormatInfo ();
  220. nfi.NumberNegativePattern = 1;
  221. nfi.readOnly = true;
  222. return nfi;
  223. }
  224. }
  225. public bool IsReadOnly {
  226. get {
  227. return readOnly;
  228. }
  229. }
  230. public string NaNSymbol {
  231. get {
  232. return naNSymbol;
  233. }
  234. set {
  235. if (value == null)
  236. throw new ArgumentNullException
  237. ("The value specified for the property is a null reference");
  238. if (readOnly)
  239. throw new InvalidOperationException
  240. ("The current instance is read-only and a set operation was attempted");
  241. naNSymbol = value;
  242. }
  243. }
  244. public string NegativeInfinitySymbol {
  245. get {
  246. return negativeInfinitySymbol;
  247. }
  248. set {
  249. if (value == null)
  250. throw new ArgumentNullException
  251. ("The value specified for the property is a null reference");
  252. if (readOnly)
  253. throw new InvalidOperationException
  254. ("The current instance is read-only and a set operation was attempted");
  255. negativeInfinitySymbol = value;
  256. }
  257. }
  258. public string NegativeSign {
  259. get {
  260. return negativeSign;
  261. }
  262. set {
  263. if (value == null)
  264. throw new ArgumentNullException
  265. ("The value specified for the property is a null reference");
  266. if (readOnly)
  267. throw new InvalidOperationException
  268. ("The current instance is read-only and a set operation was attempted");
  269. negativeSign = value;
  270. }
  271. }
  272. // =========== Number Format Properties =========== //
  273. public int NumberDecimalDigits {
  274. get {
  275. return numberDecimalDigits;
  276. }
  277. set {
  278. if (value < 0 || value > 99)
  279. throw new ArgumentOutOfRangeException
  280. ("The value specified for the property is less than 0 or greater than 99");
  281. if (readOnly)
  282. throw new InvalidOperationException
  283. ("The current instance is read-only and a set operation was attempted");
  284. numberDecimalDigits = value;
  285. }
  286. }
  287. public string NumberDecimalSeparator {
  288. get {
  289. return numberDecimalSeparator;
  290. }
  291. set {
  292. if (value == null)
  293. throw new ArgumentNullException
  294. ("The value specified for the property is a null reference");
  295. if (readOnly)
  296. throw new InvalidOperationException
  297. ("The current instance is read-only and a set operation was attempted");
  298. numberDecimalSeparator = value;
  299. }
  300. }
  301. public string NumberGroupSeparator {
  302. get {
  303. return numberGroupSeparator;
  304. }
  305. set {
  306. if (value == null)
  307. throw new ArgumentNullException
  308. ("The value specified for the property is a null reference");
  309. if (readOnly)
  310. throw new InvalidOperationException
  311. ("The current instance is read-only and a set operation was attempted");
  312. numberGroupSeparator = value;
  313. }
  314. }
  315. public int[] NumberGroupSizes {
  316. get {
  317. return numberGroupSizes;
  318. }
  319. set {
  320. if (value == null || value.Length == 0)
  321. throw new ArgumentNullException
  322. ("The value specified for the property is a null reference");
  323. if (readOnly)
  324. throw new InvalidOperationException
  325. ("The current instance is read-only and a set operation was attempted");
  326. // All elements except last need to be in range 1 - 9, last can be 0.
  327. int last = value.Length - 1;
  328. for (int i = 0; i < last; i++)
  329. if (value[i] < 1 || value[i] > 9)
  330. throw new ArgumentOutOfRangeException
  331. ("One of the elements in the array specified is not between 1 and 9");
  332. if (value[last] < 0 || value[last] > 9)
  333. throw new ArgumentOutOfRangeException
  334. ("Last element in the array specified is not between 0 and 9");
  335. numberGroupSizes = (int[]) value.Clone();
  336. }
  337. }
  338. public int NumberNegativePattern {
  339. get {
  340. // See ECMA NumberFormatInfo page 27
  341. return numberNegativePattern;
  342. }
  343. set {
  344. if (value < 0 || value > 4)
  345. throw new ArgumentOutOfRangeException
  346. ("The value specified for the property is less than 0 or greater than 15");
  347. if (readOnly)
  348. throw new InvalidOperationException
  349. ("The current instance is read-only and a set operation was attempted");
  350. numberNegativePattern = value;
  351. }
  352. }
  353. // =========== Percent Format Properties =========== //
  354. public int PercentDecimalDigits {
  355. get {
  356. return percentDecimalDigits;
  357. }
  358. set {
  359. if (value < 0 || value > 99)
  360. throw new ArgumentOutOfRangeException
  361. ("The value specified for the property is less than 0 or greater than 99");
  362. if (readOnly)
  363. throw new InvalidOperationException
  364. ("The current instance is read-only and a set operation was attempted");
  365. percentDecimalDigits = value;
  366. }
  367. }
  368. public string PercentDecimalSeparator {
  369. get {
  370. return percentDecimalSeparator;
  371. }
  372. set {
  373. if (value == null)
  374. throw new ArgumentNullException
  375. ("The value specified for the property is a null reference");
  376. if (readOnly)
  377. throw new InvalidOperationException
  378. ("The current instance is read-only and a set operation was attempted");
  379. percentDecimalSeparator = value;
  380. }
  381. }
  382. public string PercentGroupSeparator {
  383. get {
  384. return percentGroupSeparator;
  385. }
  386. set {
  387. if (value == null)
  388. throw new ArgumentNullException
  389. ("The value specified for the property is a null reference");
  390. if (readOnly)
  391. throw new InvalidOperationException
  392. ("The current instance is read-only and a set operation was attempted");
  393. percentGroupSeparator = value;
  394. }
  395. }
  396. public int[] PercentGroupSizes {
  397. get {
  398. return percentGroupSizes;
  399. }
  400. set {
  401. if (value == null || value.Length == 0)
  402. throw new ArgumentNullException
  403. ("The value specified for the property is a null reference");
  404. if (readOnly)
  405. throw new InvalidOperationException
  406. ("The current instance is read-only and a set operation was attempted");
  407. // All elements except last need to be in range 1 - 9, last can be 0.
  408. int last = value.Length - 1;
  409. for (int i = 0; i < last; i++)
  410. if (value[i] < 1 || value[i] > 9)
  411. throw new ArgumentOutOfRangeException
  412. ("One of the elements in the array specified is not between 1 and 9");
  413. if (value[last] < 0 || value[last] > 9)
  414. throw new ArgumentOutOfRangeException
  415. ("Last element in the array specified is not between 0 and 9");
  416. percentGroupSizes = (int[]) value.Clone();
  417. }
  418. }
  419. public int PercentNegativePattern {
  420. get {
  421. // See ECMA NumberFormatInfo page 8
  422. return percentNegativePattern;
  423. }
  424. set {
  425. if (value < 0 || value > 2)
  426. throw new ArgumentOutOfRangeException
  427. ("The value specified for the property is less than 0 or greater than 15");
  428. if (readOnly)
  429. throw new InvalidOperationException
  430. ("The current instance is read-only and a set operation was attempted");
  431. percentNegativePattern = value;
  432. }
  433. }
  434. public int PercentPositivePattern {
  435. get {
  436. // See ECMA NumberFormatInfo page 11
  437. return percentPositivePattern;
  438. }
  439. set {
  440. if (value < 0 || value > 2)
  441. throw new ArgumentOutOfRangeException
  442. ("The value specified for the property is less than 0 or greater than 3");
  443. if (readOnly)
  444. throw new InvalidOperationException
  445. ("The current instance is read-only and a set operation was attempted");
  446. percentPositivePattern = value;
  447. }
  448. }
  449. public string PercentSymbol {
  450. get {
  451. return percentSymbol;
  452. }
  453. set {
  454. if (value == null)
  455. throw new ArgumentNullException
  456. ("The value specified for the property is a null reference");
  457. if (readOnly)
  458. throw new InvalidOperationException
  459. ("The current instance is read-only and a set operation was attempted");
  460. percentSymbol = value;
  461. }
  462. }
  463. public string PerMilleSymbol {
  464. get {
  465. return perMilleSymbol;
  466. }
  467. set {
  468. if (value == null)
  469. throw new ArgumentNullException
  470. ("The value specified for the property is a null reference");
  471. if (readOnly)
  472. throw new InvalidOperationException
  473. ("The current instance is read-only and a set operation was attempted");
  474. perMilleSymbol = value;
  475. }
  476. }
  477. public string PositiveInfinitySymbol {
  478. get {
  479. return positiveInfinitySymbol;
  480. }
  481. set {
  482. if (value == null)
  483. throw new ArgumentNullException
  484. ("The value specified for the property is a null reference");
  485. if (readOnly)
  486. throw new InvalidOperationException
  487. ("The current instance is read-only and a set operation was attempted");
  488. positiveInfinitySymbol = value;
  489. }
  490. }
  491. public string PositiveSign {
  492. get {
  493. return positiveSign;
  494. }
  495. set {
  496. if (value == null)
  497. throw new ArgumentNullException
  498. ("The value specified for the property is a null reference");
  499. if (readOnly)
  500. throw new InvalidOperationException
  501. ("The current instance is read-only and a set operation was attempted");
  502. positiveSign = value;
  503. }
  504. }
  505. public object GetFormat (Type formatType)
  506. {
  507. return (formatType == GetType()) ? this : null;
  508. }
  509. public object Clone ()
  510. {
  511. NumberFormatInfo clone = (NumberFormatInfo) MemberwiseClone();
  512. // clone is not read only
  513. clone.readOnly = false;
  514. return clone;
  515. }
  516. public static NumberFormatInfo ReadOnly (NumberFormatInfo nfi)
  517. {
  518. NumberFormatInfo copy = (NumberFormatInfo)nfi.Clone();
  519. copy.readOnly = true;
  520. return copy;
  521. }
  522. public static NumberFormatInfo GetInstance(IFormatProvider provider)
  523. {
  524. if (provider != null) {
  525. NumberFormatInfo nfi;
  526. nfi = (NumberFormatInfo)provider.GetFormat(typeof(NumberFormatInfo));
  527. if (nfi != null)
  528. return nfi;
  529. }
  530. return CurrentInfo;
  531. }
  532. }
  533. }