2
2
using System . Collections . Generic ;
3
3
using System . Diagnostics . CodeAnalysis ;
4
4
using System . Globalization ;
5
+ using System . Linq ;
5
6
using UnitsNet . Units ;
6
7
7
8
namespace UnitsNet
@@ -40,7 +41,7 @@ public static bool TryGetUnitInfo(Enum unitEnum, [NotNullWhen(true)] out UnitInf
40
41
Default . TryGetUnitInfo ( unitEnum , out unitInfo ) ;
41
42
42
43
/// <summary>
43
- ///
44
+ ///
44
45
/// </summary>
45
46
/// <param name="unit"></param>
46
47
/// <param name="unitInfo"></param>
@@ -55,13 +56,153 @@ public static bool TryGetUnitInfo(Enum unitEnum, [NotNullWhen(true)] out UnitInf
55
56
/// <exception cref="UnitNotFoundException">Unit value is not a known unit enum type.</exception>
56
57
public static IQuantity From ( QuantityValue value , Enum unit )
57
58
{
58
- return Default . From ( value , unit ) ;
59
+ return TryFrom ( value , unit , out IQuantity ? quantity )
60
+ ? quantity
61
+ : throw new UnitNotFoundException ( $ "Unit value { unit } of type { unit . GetType ( ) } is not a known unit enum type. Expected types like UnitsNet.Units.LengthUnit. Did you pass in a custom enum type defined outside the UnitsNet library?") ;
62
+ }
63
+
64
+ /// <summary>
65
+ /// Dynamically construct a quantity from a value, the quantity name and the unit name.
66
+ /// </summary>
67
+ /// <param name="value">Numeric value.</param>
68
+ /// <param name="quantityName">The invariant quantity name, such as "Length". Does not support localization.</param>
69
+ /// <param name="unitName">The invariant unit enum name, such as "Meter". Does not support localization.</param>
70
+ /// <returns>An <see cref="IQuantity"/> object.</returns>
71
+ /// <exception cref="ArgumentException">Unit value is not a known unit enum type.</exception>
72
+ public static IQuantity From ( QuantityValue value , string quantityName , string unitName )
73
+ {
74
+ // Get enum value for this unit, f.ex. LengthUnit.Meter for unit name "Meter".
75
+ return UnitConverter . TryParseUnit ( quantityName , unitName , out Enum ? unitValue ) &&
76
+ TryFrom ( value , unitValue , out IQuantity ? quantity )
77
+ ? quantity
78
+ : throw new UnitNotFoundException ( $ "Unit [{ unitName } ] not found for quantity [{ quantityName } ].") ;
79
+ }
80
+
81
+ /// <summary>
82
+ /// Dynamically construct a quantity from a numeric value and a unit abbreviation using <see cref="CultureInfo.CurrentCulture"/>.
83
+ /// </summary>
84
+ /// <remarks>
85
+ /// This method is currently not optimized for performance and will enumerate all units and their unit abbreviations each time.<br/>
86
+ /// Unit abbreviation matching is case-insensitive.<br/>
87
+ /// <br/>
88
+ /// This will fail if more than one unit across all quantities share the same unit abbreviation.<br/>
89
+ /// Prefer <see cref="From(UnitsNet.QuantityValue,System.Enum)"/> or <see cref="From(UnitsNet.QuantityValue,string,string)"/> instead.
90
+ /// </remarks>
91
+ /// <param name="value">Numeric value.</param>
92
+ /// <param name="unitAbbreviation">Unit abbreviation, such as "kg" for <see cref="MassUnit.Kilogram"/>.</param>
93
+ /// <returns>An <see cref="IQuantity"/> object.</returns>
94
+ /// <exception cref="UnitNotFoundException">Unit abbreviation is not known.</exception>
95
+ /// <exception cref="AmbiguousUnitParseException">Multiple units found matching the given unit abbreviation.</exception>
96
+ public static IQuantity FromUnitAbbreviation ( QuantityValue value , string unitAbbreviation ) => FromUnitAbbreviation ( null , value , unitAbbreviation ) ;
97
+
98
+ /// <summary>
99
+ /// Dynamically construct a quantity from a numeric value and a unit abbreviation.
100
+ /// </summary>
101
+ /// <remarks>
102
+ /// This method is currently not optimized for performance and will enumerate all units and their unit abbreviations each time.<br/>
103
+ /// Unit abbreviation matching is case-insensitive.<br/>
104
+ /// <br/>
105
+ /// This will fail if more than one unit across all quantities share the same unit abbreviation.<br/>
106
+ /// Prefer <see cref="From(UnitsNet.QuantityValue,System.Enum)"/> or <see cref="From(UnitsNet.QuantityValue,string,string)"/> instead.
107
+ /// </remarks>
108
+ /// <param name="formatProvider">The format provider to use for lookup. Defaults to <see cref="CultureInfo.CurrentCulture" /> if null.</param>
109
+ /// <param name="value">Numeric value.</param>
110
+ /// <param name="unitAbbreviation">Unit abbreviation, such as "kg" for <see cref="MassUnit.Kilogram"/>.</param>
111
+ /// <returns>An <see cref="IQuantity"/> object.</returns>
112
+ /// <exception cref="UnitNotFoundException">Unit abbreviation is not known.</exception>
113
+ /// <exception cref="AmbiguousUnitParseException">Multiple units found matching the given unit abbreviation.</exception>
114
+ public static IQuantity FromUnitAbbreviation ( IFormatProvider ? formatProvider , QuantityValue value , string unitAbbreviation )
115
+ {
116
+ // TODO Optimize this with UnitValueAbbreviationLookup via UnitAbbreviationsCache.TryGetUnitValueAbbreviationLookup.
117
+ List < Enum > units = GetUnitsForAbbreviation ( formatProvider , unitAbbreviation ) ;
118
+ if ( units . Count > 1 )
119
+ {
120
+ throw new AmbiguousUnitParseException ( $ "Multiple units found matching the given unit abbreviation: { unitAbbreviation } ") ;
121
+ }
122
+
123
+ if ( units . Count == 0 )
124
+ {
125
+ throw new UnitNotFoundException ( $ "Unit abbreviation { unitAbbreviation } is not known. Did you pass in a custom unit abbreviation defined outside the UnitsNet library? This is currently not supported.") ;
126
+ }
127
+
128
+ Enum unit = units . Single ( ) ;
129
+ return From ( value , unit ) ;
59
130
}
60
131
61
132
/// <inheritdoc cref="TryFrom(QuantityValue,System.Enum,out UnitsNet.IQuantity)"/>
62
133
public static bool TryFrom ( double value , Enum unit , [ NotNullWhen ( true ) ] out IQuantity ? quantity )
63
134
{
64
- return Default . TryFrom ( value , unit , out quantity ) ;
135
+ quantity = default ;
136
+
137
+ // Implicit cast to QuantityValue would prevent TryFrom from being called,
138
+ // so we need to explicitly check this here for double arguments.
139
+ return ! double . IsNaN ( value ) &&
140
+ ! double . IsInfinity ( value ) &&
141
+ TryFrom ( ( QuantityValue ) value , unit , out quantity ) ;
142
+ }
143
+
144
+ /// <summary>
145
+ /// Try to dynamically construct a quantity from a value, the quantity name and the unit name.
146
+ /// </summary>
147
+ /// <param name="value">Numeric value.</param>
148
+ /// <param name="unitName">The invariant unit enum name, such as "Meter". Does not support localization.</param>
149
+ /// <param name="quantityName">The invariant quantity name, such as "Length". Does not support localization.</param>
150
+ /// <param name="quantity">The constructed quantity, if successful, otherwise null.</param>
151
+ /// <returns><c>True</c> if successful with <paramref name="quantity"/> assigned the value, otherwise <c>false</c>.</returns>
152
+ public static bool TryFrom ( double value , string quantityName , string unitName , [ NotNullWhen ( true ) ] out IQuantity ? quantity )
153
+ {
154
+ quantity = default ;
155
+
156
+ return UnitConverter . TryParseUnit ( quantityName , unitName , out Enum ? unitValue ) &&
157
+ TryFrom ( value , unitValue , out quantity ) ;
158
+ }
159
+
160
+ /// <summary>
161
+ /// Dynamically construct a quantity from a numeric value and a unit abbreviation using <see cref="CultureInfo.CurrentCulture"/>.
162
+ /// </summary>
163
+ /// <remarks>
164
+ /// This method is currently not optimized for performance and will enumerate all units and their unit abbreviations each time.<br/>
165
+ /// Unit abbreviation matching is case-insensitive.<br/>
166
+ /// <br/>
167
+ /// This will fail if more than one unit across all quantities share the same unit abbreviation.<br/>
168
+ /// Prefer <see cref="From(UnitsNet.QuantityValue,System.Enum)"/> or <see cref="From(UnitsNet.QuantityValue,string,string)"/> instead.
169
+ /// </remarks>
170
+ /// <param name="value">Numeric value.</param>
171
+ /// <param name="unitAbbreviation">Unit abbreviation, such as "kg" for <see cref="MassUnit.Kilogram"/>.</param>
172
+ /// <param name="quantity">The quantity if successful, otherwise null.</param>
173
+ /// <returns>True if successful.</returns>
174
+ /// <exception cref="ArgumentException">Unit value is not a known unit enum type.</exception>
175
+ public static bool TryFromUnitAbbreviation ( QuantityValue value , string unitAbbreviation , [ NotNullWhen ( true ) ] out IQuantity ? quantity ) =>
176
+ TryFromUnitAbbreviation ( null , value , unitAbbreviation , out quantity ) ;
177
+
178
+ /// <summary>
179
+ /// Dynamically construct a quantity from a numeric value and a unit abbreviation.
180
+ /// </summary>
181
+ /// <remarks>
182
+ /// This method is currently not optimized for performance and will enumerate all units and their unit abbreviations each time.<br/>
183
+ /// Unit abbreviation matching is case-insensitive.<br/>
184
+ /// <br/>
185
+ /// This will fail if more than one unit across all quantities share the same unit abbreviation.<br/>
186
+ /// Prefer <see cref="From(UnitsNet.QuantityValue,System.Enum)"/> or <see cref="From(UnitsNet.QuantityValue,string,string)"/> instead.
187
+ /// </remarks>
188
+ /// <param name="formatProvider">The format provider to use for lookup. Defaults to <see cref="CultureInfo.CurrentCulture" /> if null.</param>
189
+ /// <param name="value">Numeric value.</param>
190
+ /// <param name="unitAbbreviation">Unit abbreviation, such as "kg" for <see cref="MassUnit.Kilogram"/>.</param>
191
+ /// <param name="quantity">The quantity if successful, otherwise null.</param>
192
+ /// <returns>True if successful.</returns>
193
+ /// <exception cref="ArgumentException">Unit value is not a known unit enum type.</exception>
194
+ public static bool TryFromUnitAbbreviation ( IFormatProvider ? formatProvider , QuantityValue value , string unitAbbreviation , [ NotNullWhen ( true ) ] out IQuantity ? quantity )
195
+ {
196
+ // TODO Optimize this with UnitValueAbbreviationLookup via UnitAbbreviationsCache.TryGetUnitValueAbbreviationLookup.
197
+ List < Enum > units = GetUnitsForAbbreviation ( formatProvider , unitAbbreviation ) ;
198
+ if ( units . Count == 1 )
199
+ {
200
+ Enum ? unit = units . SingleOrDefault ( ) ;
201
+ return TryFrom ( value , unit , out quantity ) ;
202
+ }
203
+
204
+ quantity = default ;
205
+ return false ;
65
206
}
66
207
67
208
/// <inheritdoc cref="Parse(IFormatProvider, System.Type,string)"/>
0 commit comments