Skip to content

Added MapUnitToDefaultAbbreviation #578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions UnitsNet.Tests/UnitAbbreviationsCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,25 @@ public void MapUnitToAbbreviation_AddCustomUnit_DoesNotOverrideDefaultAbbreviati
Assert.Equal("m²", cache.GetDefaultAbbreviation(AreaUnit.SquareMeter));
}

[Fact]
public void MapUnitToDefaultAbbreviation_GivenUnitAndCulture_SetsDefaultAbbreviationForUnitAndCulture()
{
var cache = new UnitAbbreviationsCache();
cache.MapUnitToDefaultAbbreviation(AreaUnit.SquareMeter, AmericanCulture, "m^2");

Assert.Equal("m^2", cache.GetDefaultAbbreviation(AreaUnit.SquareMeter, AmericanCulture));
}

[Fact]
public void MapUnitToDefaultAbbreviation_GivenCustomAbbreviation_SetsAbbreviationUsedByQuantityToString()
{
// Use a distinct culture here so that we don't mess up other tests that may rely on the default cache.
var newZealandCulture = GetCulture("en-NZ");
UnitAbbreviationsCache.Default.MapUnitToDefaultAbbreviation(AreaUnit.SquareMeter, newZealandCulture, "m^2");

Assert.Equal("1 m^2", Area.FromSquareMeters(1).ToString(newZealandCulture));
}

/// <summary>
/// Convenience method to the proper culture parameter type.
/// </summary>
Expand Down
83 changes: 78 additions & 5 deletions UnitsNet/CustomCode/UnitAbbreviationsCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ void MapUnitToAbbreviation<TUnitType>(TUnitType unit, params string[] abbreviati
MapUnitToAbbreviation(typeof(TUnitType), Convert.ToInt32(unit), GlobalConfiguration.DefaultCulture, abbreviations);
}

/// <summary>
/// Adds a unit abbreviation for the given unit enum value and sets it as the default.
/// This is used to dynamically add abbreviations for existing unit enums such as <see cref="UnitsNet.Units.LengthUnit"/> or to extend with third-party unit enums
/// in order to <see cref="UnitParser.Parse{TUnitType}"/> or <see cref="GetDefaultAbbreviation{TUnitType}"/> on them later.
/// </summary>
/// <param name="unit">The unit enum value.</param>
/// <param name="abbreviation">Unit abbreviations to add as default.</param>
/// <typeparam name="TUnitType">The type of unit enum.</typeparam>
[PublicAPI]
// Windows Runtime Component does not allow public methods/ctors with same number of parameters: https://msdn.microsoft.com/en-us/library/br230301.aspx#Overloaded methods
#if WINDOWS_UWP
internal
#else
public
#endif
void MapUnitToDefaultAbbreviation<TUnitType>(TUnitType unit, string abbreviation) where TUnitType : Enum
{
MapUnitToDefaultAbbreviation(typeof(TUnitType), Convert.ToInt32(unit), GlobalConfiguration.DefaultCulture, abbreviation);
}

/// <summary>
/// Adds one or more unit abbreviation for the given unit enum value.
/// This is used to dynamically add abbreviations for existing unit enums such as <see cref="LengthUnit"/> or to extend with third-party unit enums
Expand Down Expand Up @@ -117,6 +137,33 @@ void MapUnitToAbbreviation<TUnitType>(TUnitType unit, IFormatProvider formatProv
MapUnitToAbbreviation(unitType, unitValue, formatProvider, abbreviations);
}

/// <summary>
/// Adds a unit abbreviation for the given unit enum value and sets it as the default.
/// This is used to dynamically add abbreviations for existing unit enums such as <see cref="LengthUnit"/> or to extend with third-party unit enums
/// in order to <see cref="UnitParser.Parse{TUnitType}"/> or <see cref="GetDefaultAbbreviation{TUnitType}"/> on them later.
/// </summary>
/// <param name="unit">The unit enum value.</param>
/// <param name="formatProvider">The format provider to use for lookup. Defaults to <see cref="GlobalConfiguration.DefaultCulture" /> if null.</param>
/// <param name="abbreviation">Unit abbreviation to add as default.</param>
/// <typeparam name="TUnitType">The type of unit enum.</typeparam>
[PublicAPI]
// Windows Runtime Component does not allow public methods/ctors with same number of parameters: https://msdn.microsoft.com/en-us/library/br230301.aspx#Overloaded methods
#if WINDOWS_UWP
internal
#else
public
#endif
void MapUnitToDefaultAbbreviation<TUnitType>(TUnitType unit, IFormatProvider formatProvider, string abbreviation) where TUnitType : Enum
{
// Assuming TUnitType is an enum, this conversion is safe. Seems not possible to enforce this today.
// Src: http://stackoverflow.com/questions/908543/how-to-convert-from-system-enum-to-base-integer
// http://stackoverflow.com/questions/79126/create-generic-method-constraining-t-to-an-enum
var unitValue = Convert.ToInt32(unit);
var unitType = typeof(TUnitType);

MapUnitToDefaultAbbreviation(unitType, unitValue, formatProvider, abbreviation);
}

/// <summary>
/// Adds one or more unit abbreviation for the given unit enum value.
/// This is used to dynamically add abbreviations for existing unit enums such as <see cref="LengthUnit"/> or to extend with third-party unit enums
Expand All @@ -134,7 +181,33 @@ void MapUnitToAbbreviation<TUnitType>(TUnitType unit, IFormatProvider formatProv
public
#endif
void MapUnitToAbbreviation(Type unitType, int unitValue, IFormatProvider formatProvider, [NotNull] params string[] abbreviations)
{
{
PerformAbbreviationMapping(unitType, unitValue, formatProvider, false, abbreviations);
}

/// <summary>
/// Adds a unit abbreviation for the given unit enum value and sets it as the default.
/// This is used to dynamically add abbreviations for existing unit enums such as <see cref="LengthUnit"/> or to extend with third-party unit enums
/// in order to <see cref="UnitParser.Parse{TUnitType}"/> or <see cref="GetDefaultAbbreviation{TUnitType}"/> on them later.
/// </summary>
/// <param name="unitType">The unit enum type.</param>
/// <param name="unitValue">The unit enum value.</param>
/// <param name="formatProvider">The format provider to use for lookup. Defaults to <see cref="GlobalConfiguration.DefaultCulture" /> if null.</param>
/// <param name="abbreviation">Unit abbreviation to add as default.</param>
[PublicAPI]
// Windows Runtime Component does not allow public methods/ctors with same number of parameters: https://msdn.microsoft.com/en-us/library/br230301.aspx#Overloaded methods
#if WINDOWS_UWP
internal
#else
public
#endif
void MapUnitToDefaultAbbreviation(Type unitType, int unitValue, IFormatProvider formatProvider, [NotNull] string abbreviation)
{
PerformAbbreviationMapping(unitType, unitValue, formatProvider, true, abbreviation);
}

private void PerformAbbreviationMapping(Type unitType, int unitValue, IFormatProvider formatProvider, bool setAsDefault, [NotNull] params string[] abbreviations)
{
if (!unitType.IsEnum())
throw new ArgumentException("Must be an enum type.", nameof(unitType));

Expand All @@ -143,15 +216,15 @@ void MapUnitToAbbreviation(Type unitType, int unitValue, IFormatProvider formatP

formatProvider = formatProvider ?? GlobalConfiguration.DefaultCulture;

if(!_lookupsForCulture.TryGetValue(formatProvider, out var quantitiesForProvider))
if (!_lookupsForCulture.TryGetValue(formatProvider, out var quantitiesForProvider))
quantitiesForProvider = _lookupsForCulture[formatProvider] = new UnitTypeToLookup();

if(!quantitiesForProvider.TryGetValue(unitType, out var unitToAbbreviations))
if (!quantitiesForProvider.TryGetValue(unitType, out var unitToAbbreviations))
unitToAbbreviations = quantitiesForProvider[unitType] = new UnitValueAbbreviationLookup();

foreach(var abbr in abbreviations)
foreach (var abbr in abbreviations)
{
unitToAbbreviations.Add(unitValue, abbr);
unitToAbbreviations.Add(unitValue, abbr, setAsDefault);
}
}

Expand Down
10 changes: 8 additions & 2 deletions UnitsNet/CustomCode/UnitValueAbbreviationLookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,21 @@ internal List<int> GetUnitsForAbbreviation(string abbreviation)
return units.Distinct().ToList();
}

internal void Add(int unit, string abbreviation)
internal void Add(int unit, string abbreviation, bool setAsDefault = false)
{
if(!unitToAbbreviationMap.TryGetValue(unit, out var abbreviationsForUnit))
abbreviationsForUnit = unitToAbbreviationMap[unit] = new List<string>();

if(!abbreviationToUnitMap.TryGetValue(abbreviation, out var unitsForAbbreviation))
abbreviationToUnitMap[abbreviation] = unitsForAbbreviation = new List<int>();

abbreviationsForUnit.Add(abbreviation);
abbreviationsForUnit.Remove(abbreviation);
unitsForAbbreviation.Remove(unit);

if (setAsDefault)
abbreviationsForUnit.Insert(0, abbreviation);
else
abbreviationsForUnit.Add(abbreviation);
unitsForAbbreviation.Add(unit);
}
}
Expand Down