Skip to content

Commit

Permalink
fixup! Move unit abbreviation strings into culture-specific resource …
Browse files Browse the repository at this point in the history
…files (#1210)

Fixes 37ada11 when merging #1210

The PR incorrectly handled some merge conflicts and wound up deleting code.
Regenerate code.
  • Loading branch information
angularsen committed Jun 18, 2023
1 parent 37ada11 commit d59bfe6
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 79 deletions.
6 changes: 3 additions & 3 deletions UnitsNet.Tests/CustomQuantities/HowMuch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public HowMuch(double value, HowMuchUnit unit)
typeof(HowMuchUnit),
new UnitInfo[]
{
new UnitInfo<HowMuchUnit>(HowMuchUnit.Some, "Some", BaseUnits.Undefined),
new UnitInfo<HowMuchUnit>(HowMuchUnit.ATon, "Tons", BaseUnits.Undefined),
new UnitInfo<HowMuchUnit>(HowMuchUnit.AShitTon, "ShitTons", BaseUnits.Undefined),
new UnitInfo<HowMuchUnit>(HowMuchUnit.Some, "Some", BaseUnits.Undefined, nameof(HowMuch)),
new UnitInfo<HowMuchUnit>(HowMuchUnit.ATon, "Tons", BaseUnits.Undefined, nameof(HowMuch)),
new UnitInfo<HowMuchUnit>(HowMuchUnit.AShitTon, "ShitTons", BaseUnits.Undefined, nameof(HowMuch)),
},
HowMuchUnit.Some,
Zero,
Expand Down
22 changes: 11 additions & 11 deletions UnitsNet.Tests/QuantityInfoTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ public void Constructor_AssignsProperties()
{
var expectedZero = Length.FromCentimeters(10);
UnitInfo[] expectedUnitInfos = {
new(LengthUnit.Centimeter, "Centimeters", new BaseUnits(LengthUnit.Centimeter)),
new(LengthUnit.Kilometer, "Kilometers", new BaseUnits(LengthUnit.Kilometer))
new(LengthUnit.Centimeter, "Centimeters", new BaseUnits(LengthUnit.Centimeter), nameof(Length)),
new(LengthUnit.Kilometer, "Kilometers", new BaseUnits(LengthUnit.Kilometer), nameof(Length))
};
var expectedBaseUnit = LengthUnit.Centimeter;
var expectedBaseDimensions = Length.BaseDimensions;
Expand All @@ -39,9 +39,9 @@ public void Constructor_AssignsPropertiesForCustomQuantity()
{
var expectedZero = new HowMuch(10, HowMuchUnit.Some);
UnitInfo[] expectedUnitInfos = {
new(HowMuchUnit.Some, "Some", BaseUnits.Undefined),
new(HowMuchUnit.ATon, "Tons", BaseUnits.Undefined),
new(HowMuchUnit.AShitTon, "ShitTons", BaseUnits.Undefined)
new(HowMuchUnit.Some, "Some", BaseUnits.Undefined, nameof(HowMuch)),
new(HowMuchUnit.ATon, "Tons", BaseUnits.Undefined, nameof(HowMuch)),
new(HowMuchUnit.AShitTon, "ShitTons", BaseUnits.Undefined, nameof(HowMuch))
};
var expectedBaseUnit = HowMuchUnit.Some;
var expectedBaseDimensions = BaseDimensions.Dimensionless;
Expand All @@ -60,8 +60,8 @@ public void GenericsConstructor_AssignsProperties()
{
var expectedZero = Length.FromCentimeters(10);
UnitInfo<LengthUnit>[] expectedUnitInfos = {
new(LengthUnit.Centimeter, "Centimeters", new BaseUnits(LengthUnit.Centimeter)),
new(LengthUnit.Kilometer,"Kilometers", new BaseUnits(LengthUnit.Kilometer))
new(LengthUnit.Centimeter, "Centimeters", new BaseUnits(LengthUnit.Centimeter), nameof(Length)),
new(LengthUnit.Kilometer,"Kilometers", new BaseUnits(LengthUnit.Kilometer), nameof(Length))
};
var expectedBaseUnit = LengthUnit.Centimeter;
var expectedBaseDimensions = Length.BaseDimensions;
Expand Down Expand Up @@ -204,8 +204,8 @@ public void GetUnitInfoFor_GivenBaseUnitsWithMultipleMatches_ThrowsInvalidOperat

var quantityInfo = new QuantityInfo<LengthUnit>(Length.Info.Name,
new UnitInfo<LengthUnit>[] {
new(LengthUnit.Meter, "Meters", baseUnits),
new(LengthUnit.Foot, "Feet", baseUnits)
new(LengthUnit.Meter, "Meters", baseUnits, nameof(Length)),
new(LengthUnit.Foot, "Feet", baseUnits, nameof(Length))
},
LengthUnit.Meter, Length.Zero, Length.BaseDimensions);

Expand Down Expand Up @@ -242,8 +242,8 @@ public void GetUnitInfosFor_GivenBaseUnitsWithMultipleMatches_ReturnsMultipleMat

var quantityInfo = new QuantityInfo<LengthUnit>(Length.Info.Name,
new UnitInfo<LengthUnit>[] {
new(LengthUnit.Meter, "Meters", baseUnits),
new(LengthUnit.Foot, "Feet", baseUnits) },
new(LengthUnit.Meter, "Meters", baseUnits, nameof(Length)),
new(LengthUnit.Foot, "Feet", baseUnits, nameof(Length)) },
LengthUnit.Meter, Length.Zero, Length.BaseDimensions);

var result = quantityInfo.GetUnitInfosFor(baseUnits);
Expand Down
2 changes: 1 addition & 1 deletion UnitsNet.Tests/QuantityTypeConverterTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ public void ConvertFrom_GivenEmptyString_ThrowsNotSupportedException()
}

[Fact]
public void ConvertFrom_GivenWrongQuantity_ThrowsArgumentException()
public void ConvertFrom_GivenWrongQuantity_ThrowsUnitNotFoundException()
{
var converter = new QuantityTypeConverter<Length>();
ITypeDescriptorContext context = new TypeDescriptorContext("SomeMemberName", new Attribute[] { });
Expand Down
4 changes: 2 additions & 2 deletions UnitsNet.Tests/UnitInfoTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ public class UnitInfoTests
[Fact]
public void ConstructorTest()
{
var unitInfo = new UnitInfo(LengthUnit.Meter, "Meters", new BaseUnits(LengthUnit.Meter));
var unitInfo = new UnitInfo(LengthUnit.Meter, "Meters", new BaseUnits(LengthUnit.Meter), nameof(Length));
Assert.Equal(LengthUnit.Meter, unitInfo.Value);
Assert.Equal(LengthUnit.Meter.ToString(), unitInfo.Name);
}

[Fact]
public void GenericConstructorTest()
{
var unitInfo = new UnitInfo<LengthUnit>(LengthUnit.Meter, "Meters", new BaseUnits(LengthUnit.Meter));
var unitInfo = new UnitInfo<LengthUnit>(LengthUnit.Meter, "Meters", new BaseUnits(LengthUnit.Meter), nameof(Length));
Assert.Equal(LengthUnit.Meter, unitInfo.Value);
Assert.Equal(LengthUnit.Meter.ToString(), unitInfo.Name);
}
Expand Down
147 changes: 144 additions & 3 deletions UnitsNet/CustomCode/Quantity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using UnitsNet.Units;

namespace UnitsNet
Expand Down Expand Up @@ -40,7 +41,7 @@ public static bool TryGetUnitInfo(Enum unitEnum, [NotNullWhen(true)] out UnitInf
Default.TryGetUnitInfo(unitEnum, out unitInfo);

/// <summary>
///
///
/// </summary>
/// <param name="unit"></param>
/// <param name="unitInfo"></param>
Expand All @@ -55,13 +56,153 @@ public static bool TryGetUnitInfo(Enum unitEnum, [NotNullWhen(true)] out UnitInf
/// <exception cref="UnitNotFoundException">Unit value is not a known unit enum type.</exception>
public static IQuantity From(QuantityValue value, Enum unit)
{
return Default.From(value, unit);
return TryFrom(value, unit, out IQuantity? quantity)
? quantity
: 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?");
}

/// <summary>
/// Dynamically construct a quantity from a value, the quantity name and the unit name.
/// </summary>
/// <param name="value">Numeric value.</param>
/// <param name="quantityName">The invariant quantity name, such as "Length". Does not support localization.</param>
/// <param name="unitName">The invariant unit enum name, such as "Meter". Does not support localization.</param>
/// <returns>An <see cref="IQuantity"/> object.</returns>
/// <exception cref="ArgumentException">Unit value is not a known unit enum type.</exception>
public static IQuantity From(QuantityValue value, string quantityName, string unitName)
{
// Get enum value for this unit, f.ex. LengthUnit.Meter for unit name "Meter".
return UnitConverter.TryParseUnit(quantityName, unitName, out Enum? unitValue) &&
TryFrom(value, unitValue, out IQuantity? quantity)
? quantity
: throw new UnitNotFoundException($"Unit [{unitName}] not found for quantity [{quantityName}].");
}

/// <summary>
/// Dynamically construct a quantity from a numeric value and a unit abbreviation using <see cref="CultureInfo.CurrentCulture"/>.
/// </summary>
/// <remarks>
/// This method is currently not optimized for performance and will enumerate all units and their unit abbreviations each time.<br/>
/// Unit abbreviation matching is case-insensitive.<br/>
/// <br/>
/// This will fail if more than one unit across all quantities share the same unit abbreviation.<br/>
/// Prefer <see cref="From(UnitsNet.QuantityValue,System.Enum)"/> or <see cref="From(UnitsNet.QuantityValue,string,string)"/> instead.
/// </remarks>
/// <param name="value">Numeric value.</param>
/// <param name="unitAbbreviation">Unit abbreviation, such as "kg" for <see cref="MassUnit.Kilogram"/>.</param>
/// <returns>An <see cref="IQuantity"/> object.</returns>
/// <exception cref="UnitNotFoundException">Unit abbreviation is not known.</exception>
/// <exception cref="AmbiguousUnitParseException">Multiple units found matching the given unit abbreviation.</exception>
public static IQuantity FromUnitAbbreviation(QuantityValue value, string unitAbbreviation) => FromUnitAbbreviation(null, value, unitAbbreviation);

/// <summary>
/// Dynamically construct a quantity from a numeric value and a unit abbreviation.
/// </summary>
/// <remarks>
/// This method is currently not optimized for performance and will enumerate all units and their unit abbreviations each time.<br/>
/// Unit abbreviation matching is case-insensitive.<br/>
/// <br/>
/// This will fail if more than one unit across all quantities share the same unit abbreviation.<br/>
/// Prefer <see cref="From(UnitsNet.QuantityValue,System.Enum)"/> or <see cref="From(UnitsNet.QuantityValue,string,string)"/> instead.
/// </remarks>
/// <param name="formatProvider">The format provider to use for lookup. Defaults to <see cref="CultureInfo.CurrentCulture" /> if null.</param>
/// <param name="value">Numeric value.</param>
/// <param name="unitAbbreviation">Unit abbreviation, such as "kg" for <see cref="MassUnit.Kilogram"/>.</param>
/// <returns>An <see cref="IQuantity"/> object.</returns>
/// <exception cref="UnitNotFoundException">Unit abbreviation is not known.</exception>
/// <exception cref="AmbiguousUnitParseException">Multiple units found matching the given unit abbreviation.</exception>
public static IQuantity FromUnitAbbreviation(IFormatProvider? formatProvider, QuantityValue value, string unitAbbreviation)
{
// TODO Optimize this with UnitValueAbbreviationLookup via UnitAbbreviationsCache.TryGetUnitValueAbbreviationLookup.
List<Enum> units = GetUnitsForAbbreviation(formatProvider, unitAbbreviation);
if (units.Count > 1)
{
throw new AmbiguousUnitParseException($"Multiple units found matching the given unit abbreviation: {unitAbbreviation}");
}

if (units.Count == 0)
{
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.");
}

Enum unit = units.Single();
return From(value, unit);
}

/// <inheritdoc cref="TryFrom(QuantityValue,System.Enum,out UnitsNet.IQuantity)"/>
public static bool TryFrom(double value, Enum unit, [NotNullWhen(true)] out IQuantity? quantity)
{
return Default.TryFrom(value, unit, out quantity);
quantity = default;

// Implicit cast to QuantityValue would prevent TryFrom from being called,
// so we need to explicitly check this here for double arguments.
return !double.IsNaN(value) &&
!double.IsInfinity(value) &&
TryFrom((QuantityValue)value, unit, out quantity);
}

/// <summary>
/// Try to dynamically construct a quantity from a value, the quantity name and the unit name.
/// </summary>
/// <param name="value">Numeric value.</param>
/// <param name="unitName">The invariant unit enum name, such as "Meter". Does not support localization.</param>
/// <param name="quantityName">The invariant quantity name, such as "Length". Does not support localization.</param>
/// <param name="quantity">The constructed quantity, if successful, otherwise null.</param>
/// <returns><c>True</c> if successful with <paramref name="quantity"/> assigned the value, otherwise <c>false</c>.</returns>
public static bool TryFrom(double value, string quantityName, string unitName, [NotNullWhen(true)] out IQuantity? quantity)
{
quantity = default;

return UnitConverter.TryParseUnit(quantityName, unitName, out Enum? unitValue) &&
TryFrom(value, unitValue, out quantity);
}

/// <summary>
/// Dynamically construct a quantity from a numeric value and a unit abbreviation using <see cref="CultureInfo.CurrentCulture"/>.
/// </summary>
/// <remarks>
/// This method is currently not optimized for performance and will enumerate all units and their unit abbreviations each time.<br/>
/// Unit abbreviation matching is case-insensitive.<br/>
/// <br/>
/// This will fail if more than one unit across all quantities share the same unit abbreviation.<br/>
/// Prefer <see cref="From(UnitsNet.QuantityValue,System.Enum)"/> or <see cref="From(UnitsNet.QuantityValue,string,string)"/> instead.
/// </remarks>
/// <param name="value">Numeric value.</param>
/// <param name="unitAbbreviation">Unit abbreviation, such as "kg" for <see cref="MassUnit.Kilogram"/>.</param>
/// <param name="quantity">The quantity if successful, otherwise null.</param>
/// <returns>True if successful.</returns>
/// <exception cref="ArgumentException">Unit value is not a known unit enum type.</exception>
public static bool TryFromUnitAbbreviation(QuantityValue value, string unitAbbreviation, [NotNullWhen(true)] out IQuantity? quantity) =>
TryFromUnitAbbreviation(null, value, unitAbbreviation, out quantity);

/// <summary>
/// Dynamically construct a quantity from a numeric value and a unit abbreviation.
/// </summary>
/// <remarks>
/// This method is currently not optimized for performance and will enumerate all units and their unit abbreviations each time.<br/>
/// Unit abbreviation matching is case-insensitive.<br/>
/// <br/>
/// This will fail if more than one unit across all quantities share the same unit abbreviation.<br/>
/// Prefer <see cref="From(UnitsNet.QuantityValue,System.Enum)"/> or <see cref="From(UnitsNet.QuantityValue,string,string)"/> instead.
/// </remarks>
/// <param name="formatProvider">The format provider to use for lookup. Defaults to <see cref="CultureInfo.CurrentCulture" /> if null.</param>
/// <param name="value">Numeric value.</param>
/// <param name="unitAbbreviation">Unit abbreviation, such as "kg" for <see cref="MassUnit.Kilogram"/>.</param>
/// <param name="quantity">The quantity if successful, otherwise null.</param>
/// <returns>True if successful.</returns>
/// <exception cref="ArgumentException">Unit value is not a known unit enum type.</exception>
public static bool TryFromUnitAbbreviation(IFormatProvider? formatProvider, QuantityValue value, string unitAbbreviation, [NotNullWhen(true)] out IQuantity? quantity)
{
// TODO Optimize this with UnitValueAbbreviationLookup via UnitAbbreviationsCache.TryGetUnitValueAbbreviationLookup.
List<Enum> units = GetUnitsForAbbreviation(formatProvider, unitAbbreviation);
if (units.Count == 1)
{
Enum? unit = units.SingleOrDefault();
return TryFrom(value, unit, out quantity);
}

quantity = default;
return false;
}

/// <inheritdoc cref="Parse(IFormatProvider, System.Type,string)"/>
Expand Down
Loading

0 comments on commit d59bfe6

Please sign in to comment.