22using System . Collections . Generic ;
33using System . Diagnostics . CodeAnalysis ;
44using System . Globalization ;
5+ using System . Linq ;
56using UnitsNet . Units ;
67
78namespace UnitsNet
@@ -40,7 +41,7 @@ public static bool TryGetUnitInfo(Enum unitEnum, [NotNullWhen(true)] out UnitInf
4041 Default . TryGetUnitInfo ( unitEnum , out unitInfo ) ;
4142
4243 /// <summary>
43- ///
44+ ///
4445 /// </summary>
4546 /// <param name="unit"></param>
4647 /// <param name="unitInfo"></param>
@@ -55,13 +56,153 @@ public static bool TryGetUnitInfo(Enum unitEnum, [NotNullWhen(true)] out UnitInf
5556 /// <exception cref="UnitNotFoundException">Unit value is not a known unit enum type.</exception>
5657 public static IQuantity From ( QuantityValue value , Enum unit )
5758 {
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 ) ;
59130 }
60131
61132 /// <inheritdoc cref="TryFrom(QuantityValue,System.Enum,out UnitsNet.IQuantity)"/>
62133 public static bool TryFrom ( double value , Enum unit , [ NotNullWhen ( true ) ] out IQuantity ? quantity )
63134 {
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 ;
65206 }
66207
67208 /// <inheritdoc cref="Parse(IFormatProvider, System.Type,string)"/>
0 commit comments