|
1 |
| -// Copyright © 2007 Andreas Gullberg Larsen (angularsen@gmail.com). |
| 1 | +// Copyright (c) 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). |
2 | 2 | // https://github.com/angularsen/UnitsNet
|
3 |
| -// |
| 3 | +// |
4 | 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy
|
5 | 5 | // of this software and associated documentation files (the "Software"), to deal
|
6 | 6 | // in the Software without restriction, including without limitation the rights
|
7 | 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8 | 8 | // copies of the Software, and to permit persons to whom the Software is
|
9 | 9 | // furnished to do so, subject to the following conditions:
|
10 |
| -// |
| 10 | +// |
11 | 11 | // The above copyright notice and this permission notice shall be included in
|
12 | 12 | // all copies or substantial portions of the Software.
|
13 |
| -// |
| 13 | +// |
14 | 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15 | 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16 | 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20 | 20 | // THE SOFTWARE.
|
21 | 21 |
|
22 | 22 | // Operator overloads not supported in Windows Runtime Components, we use 'double' type instead
|
| 23 | + |
23 | 24 | #if !WINDOWS_UWP
|
24 | 25 | using System;
|
25 | 26 |
|
26 | 27 | namespace UnitsNet
|
27 | 28 | {
|
28 | 29 | /// <summary>
|
29 |
| - /// Pass it any numeric value (int, double, decimal, float..) and it will be implicitly converted to a <see cref="double" />, the quantity value representation used in UnitsNet. |
30 |
| - /// This is used to avoid an explosion of overloads for methods taking N numeric types for all our 500+ units. |
| 30 | + /// A type that supports implicit cast from all .NET numeric types, in order to avoid a large number of overloads |
| 31 | + /// and binary size for all From(value, unit) factory methods, for each of the 700+ units in the library. |
| 32 | + /// <see cref="QuantityValue"/> stores the value internally with the proper type to preserve the range or precision of the original value: |
| 33 | + /// <list type="bullet"> |
| 34 | + /// <item><description><see cref="double"/> for [byte, short, int, long, float, double]</description></item> |
| 35 | + /// <item><description><see cref="decimal"/> for [decimal] to preserve the 128-bit precision</description></item> |
| 36 | + /// </list> |
31 | 37 | /// </summary>
|
32 | 38 | /// <remarks>
|
33 |
| - /// At the time of this writing, this reduces the number of From() overloads to 1/4th: |
| 39 | + /// At the time of this writing, this reduces the number of From(value, unit) overloads to 1/4th: |
34 | 40 | /// From 8 (int, long, double, decimal + each nullable) down to 2 (QuantityValue and QuantityValue?).
|
35 | 41 | /// This also adds more numeric types with no extra overhead, such as float, short and byte.
|
36 | 42 | /// </remarks>
|
37 | 43 | public struct QuantityValue
|
38 | 44 | {
|
39 |
| - private readonly double _value; |
| 45 | + /// <summary> |
| 46 | + /// Value assigned when implicitly casting from all numeric types except <see cref="decimal" />, since |
| 47 | + /// <see cref="double" /> has the greatest range and is 64 bits versus 128 bits for <see cref="decimal"/>. |
| 48 | + /// </summary> |
| 49 | + private readonly double? _value; |
| 50 | + |
| 51 | + /// <summary> |
| 52 | + /// Value assigned when implicitly casting from <see cref="decimal" /> type, since it has a greater precision than |
| 53 | + /// <see cref="double"/> and we want to preserve that when constructing quantities that use <see cref="decimal"/> |
| 54 | + /// as their value type. |
| 55 | + /// </summary> |
| 56 | + private readonly decimal? _valueDecimal; |
40 | 57 |
|
41 |
| - // Obsolete is used to communicate how they should use this type, instead of making the constructor private and have them figure it out |
42 |
| - [Obsolete("Do not use this constructor. Instead pass any numeric value such as int, long, float, double, decimal, short or byte directly and it will be implicitly casted to double.")] |
43 | 58 | private QuantityValue(double val)
|
44 | 59 | {
|
45 | 60 | _value = val;
|
| 61 | + _valueDecimal = null; |
| 62 | + } |
| 63 | + |
| 64 | + private QuantityValue(decimal val) |
| 65 | + { |
| 66 | + _valueDecimal = val; |
| 67 | + _value = null; |
46 | 68 | }
|
47 | 69 |
|
48 | 70 | #region To QuantityValue
|
49 | 71 |
|
50 | 72 | #pragma warning disable 618
|
51 |
| - public static implicit operator QuantityValue(double val) => new QuantityValue(val); |
52 |
| - public static implicit operator QuantityValue(float val) => new QuantityValue(val); |
53 |
| - public static implicit operator QuantityValue(long val) => new QuantityValue(val); |
54 |
| - public static implicit operator QuantityValue(decimal val) => new QuantityValue(Convert.ToDouble(val)); |
55 |
| - public static implicit operator QuantityValue(short val) => new QuantityValue(val); |
56 |
| - public static implicit operator QuantityValue(byte val) => new QuantityValue(val); |
| 73 | + // Prefer double for integer types, since most quantities use that type as of now and |
| 74 | + // that avoids unnecessary casts back and forth. |
| 75 | + // If we later change to use decimal more, we should revisit this. |
| 76 | + public static implicit operator QuantityValue(byte val) => new QuantityValue((double) val); |
| 77 | + public static implicit operator QuantityValue(short val) => new QuantityValue((double) val); |
| 78 | + public static implicit operator QuantityValue(int val) => new QuantityValue((double) val); |
| 79 | + public static implicit operator QuantityValue(long val) => new QuantityValue((double) val); |
| 80 | + public static implicit operator QuantityValue(float val) => new QuantityValue(val); // double |
| 81 | + public static implicit operator QuantityValue(double val) => new QuantityValue(val); // double |
| 82 | + public static implicit operator QuantityValue(decimal val) => new QuantityValue(val); // decimal |
57 | 83 | #pragma warning restore 618
|
58 |
| - |
| 84 | + |
59 | 85 | #endregion
|
60 | 86 |
|
61 | 87 | #region To double
|
62 | 88 |
|
63 |
| - public static explicit operator double(QuantityValue number) => Convert.ToDouble(number._value); |
| 89 | + public static explicit operator double(QuantityValue number) |
| 90 | + { |
| 91 | + // double -> decimal -> zero (since we can't implement the default struct ctor) |
| 92 | + return number._value.GetValueOrDefault((double) number._valueDecimal.GetValueOrDefault()); |
| 93 | + } |
| 94 | + |
| 95 | + #endregion |
| 96 | + |
| 97 | + #region To decimal |
| 98 | + |
| 99 | + public static explicit operator decimal(QuantityValue number) |
| 100 | + { |
| 101 | + // decimal -> double -> zero (since we can't implement the default struct ctor) |
| 102 | + return number._valueDecimal.GetValueOrDefault((decimal) number._value.GetValueOrDefault()); |
| 103 | + } |
64 | 104 |
|
65 | 105 | #endregion
|
66 | 106 | }
|
|
0 commit comments