Skip to content

Commit 9fa0258

Browse files
committed
Fix #36 Throws exception on ToString() for cultures with no unit...
...abbreviations Fall back to default culture, then fall back to default abbreviation * Add test GetDefaultAbbreviationFallsBackToUsEnglishCulture Fixes #36 #36
1 parent 24f2f1a commit 9fa0258

File tree

2 files changed

+66
-21
lines changed

2 files changed

+66
-21
lines changed

Src/UnitsNet/CustomCode/UnitSystem.cs

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,12 @@ namespace UnitsNet
3434
public partial class UnitSystem
3535
{
3636
private static readonly Dictionary<CultureInfo, UnitSystem> CultureToInstance;
37+
private static readonly CultureInfo DefaultCulture = CultureInfo.GetCultureInfo("en-US");
3738

3839
/// <summary>
3940
/// The culture of which this unit system is based on. Either passed in to constructor or the default culture.
4041
/// </summary>
41-
[PublicAPI] public readonly CultureInfo Culture;
42+
[NotNull] [PublicAPI] public readonly CultureInfo Culture;
4243

4344
/// <summary>
4445
/// Per-unit-type dictionary of enum values by abbreviation. This is the inverse of
@@ -66,7 +67,7 @@ static UnitSystem()
6667
public UnitSystem([CanBeNull] CultureInfo cultureInfo = null)
6768
{
6869
if (cultureInfo == null)
69-
cultureInfo = new CultureInfo("en-US");
70+
cultureInfo = new CultureInfo(DefaultCulture.Name);
7071

7172
Culture = cultureInfo;
7273
_unitTypeToUnitValueToAbbrevs = new Dictionary<Type, Dictionary<int, List<string>>>();
@@ -75,6 +76,11 @@ public UnitSystem([CanBeNull] CultureInfo cultureInfo = null)
7576
LoadDefaultAbbreviatons(cultureInfo);
7677
}
7778

79+
public bool IsDefaultCulture
80+
{
81+
get { return Culture.Equals(DefaultCulture); }
82+
}
83+
7884
[PublicAPI]
7985
public static void ClearCache()
8086
{
@@ -145,7 +151,7 @@ public string GetDefaultAbbreviation<TUnit>(TUnit unit)
145151
public void MapUnitToAbbreviation<TUnit>(TUnit unit, params string[] abbreviations)
146152
where TUnit : /*Enum constraint hack*/ struct, IComparable, IFormattable
147153
{
148-
// Assuming TUnit is an enum, this conversion is safe. Not possible to cleanly enforce this today.
154+
// Assuming TUnit is an enum, this conversion is safe. Seems not possible to enforce this today.
149155
// Src: http://stackoverflow.com/questions/908543/how-to-convert-from-system-enum-to-base-integer
150156
// http://stackoverflow.com/questions/79126/create-generic-method-constraining-t-to-an-enum
151157
int unitValue = Convert.ToInt32(unit);
@@ -197,22 +203,31 @@ public bool TryParse<TUnit>(string unitAbbreviation, out TUnit unit)
197203
Type unitType = typeof (TUnit);
198204

199205
Dictionary<string, int> abbrevToUnitValue;
200-
if (!_unitTypeToAbbrevToUnitValue.TryGetValue(unitType, out abbrevToUnitValue))
201-
throw new NotImplementedException(
202-
string.Format("No abbreviations defined for unit type [{0}] for culture [{1}].", unitType,
203-
Culture.EnglishName));
204-
205206
int unitValue;
206-
if (!abbrevToUnitValue.TryGetValue(unitAbbreviation, out unitValue))
207+
208+
if (!_unitTypeToAbbrevToUnitValue.TryGetValue(unitType, out abbrevToUnitValue) ||
209+
!abbrevToUnitValue.TryGetValue(unitAbbreviation, out unitValue))
207210
{
208-
unit = default(TUnit);
209-
return false;
211+
if (IsDefaultCulture)
212+
{
213+
unit = default(TUnit);
214+
return false;
215+
}
216+
217+
// Fall back to default culture
218+
return GetCached(DefaultCulture).TryParse(unitAbbreviation, out unit);
210219
}
211220

212221
unit = (TUnit) (object) unitValue;
213222
return true;
214223
}
215224

225+
/// <summary>
226+
/// Get all abbreviations for unit.
227+
/// </summary>
228+
/// <typeparam name="TUnit">Enum type for units.</typeparam>
229+
/// <param name="unit">Enum value for unit.</param>
230+
/// <returns>Unit abbreviations associated with unit.</returns>
216231
[PublicAPI]
217232
public string[] GetAllAbbreviations<TUnit>(TUnit unit)
218233
where TUnit : /*Enum constraint hack*/ struct, IComparable, IFormattable
@@ -221,18 +236,20 @@ public string[] GetAllAbbreviations<TUnit>(TUnit unit)
221236
int unitValue = Convert.ToInt32(unit);
222237

223238
Dictionary<int, List<string>> unitValueToAbbrevs;
224-
if (!_unitTypeToUnitValueToAbbrevs.TryGetValue(unitType, out unitValueToAbbrevs))
225-
throw new NotImplementedException(
226-
string.Format("No abbreviations defined for unit type [{0}] for culture [{1}].", unitType,
227-
Culture.EnglishName));
228-
229239
List<string> abbrevs;
230-
if (!unitValueToAbbrevs.TryGetValue(unitValue, out abbrevs))
231-
throw new NotImplementedException(
232-
string.Format("No abbreviations defined for unit type [{0}.{1}] for culture [{2}].", unitType,
233-
unitValue, Culture.EnglishName));
234240

235-
// Return the first (most commonly used) abbreviation for this unit)
241+
if (!_unitTypeToUnitValueToAbbrevs.TryGetValue(unitType, out unitValueToAbbrevs) ||
242+
!unitValueToAbbrevs.TryGetValue(unitValue, out abbrevs))
243+
{
244+
if (IsDefaultCulture)
245+
{
246+
return new[] {string.Format("(no abbreviation for {0})", unit.ToString())};
247+
}
248+
249+
// Fall back to default culture
250+
return GetCached(DefaultCulture).GetAllAbbreviations(unit);
251+
}
252+
236253
return abbrevs.ToArray();
237254
}
238255

Tests/UnitSystemTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,15 @@ private static IEnumerable<object> GetUnitTypesWithMissingAbbreviations<TUnit>(s
5555
return unitsMissingAbbreviations.Cast<object>();
5656
}
5757

58+
private enum CustomUnit
59+
{
60+
// ReSharper disable UnusedMember.Local
61+
Undefined = 0,
62+
Unit1,
63+
Unit2
64+
// ReSharper restore UnusedMember.Local
65+
}
66+
5867
[Test]
5968
public void AllUnitAbbreviationsImplemented([Values("en-US", "nb-NO", "ru-RU")] string cultureName)
6069
{
@@ -174,6 +183,25 @@ public void AllUnitsImplementToStringForRussian()
174183
}
175184
}
176185

186+
[Test]
187+
public void GetDefaultAbbreviationFallsBackToUsEnglishCulture()
188+
{
189+
// CurrentCulture affects number formatting, such as comma or dot as decimal separator.
190+
// CurrentUICulture affects localization, in this case the abbreviation.
191+
// Zulu (South Africa)
192+
UnitSystem zuluUnits = UnitSystem.GetCached(CultureInfo.GetCultureInfo("zu-ZA"));
193+
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = zuluUnits.Culture;
194+
195+
UnitSystem usUnits = UnitSystem.GetCached(CultureInfo.GetCultureInfo("en-US"));
196+
usUnits.MapUnitToAbbreviation(CustomUnit.Unit1, "US english abbreviation for Unit1");
197+
198+
// Act
199+
string abbreviation = zuluUnits.GetDefaultAbbreviation(CustomUnit.Unit1);
200+
201+
// Assert
202+
Assert.AreEqual("US english abbreviation for Unit1", abbreviation);
203+
}
204+
177205
[Test]
178206
public void ToStringRoundsToTwoDecimals()
179207
{

0 commit comments

Comments
 (0)