From 90906236bf9633857253745e89aba3a67511c3ac Mon Sep 17 00:00:00 2001 From: lipchev Date: Fri, 3 Jan 2025 00:16:11 +0200 Subject: [PATCH] Update the ToString format of the BaseUnits/Dimensions (#1486) - `BaseUnits`: no longer using the `AbbeviationsCache`, the new format is `L=Meter, M=Kilogram, T=Second` - `BaseDimensions`: the exponent moved inside the dimension-brackets: `[Length][Time^-1]` - `BaseDimensions`: minor performance improvements As mentioned in #1452, the main motivation here is the removal of the potential side effects of accessing/loading the unit abbreviations (e.g. during the `QuantityInfo` construction) --- UnitsNet.Tests/BaseDimensionsTests.cs | 7 +-- UnitsNet.Tests/BaseUnitsTests.cs | 25 ++++++----- UnitsNet/BaseDimensions.cs | 31 ++++++++----- UnitsNet/BaseUnits.cs | 64 +++++++++++++++++---------- 4 files changed, 80 insertions(+), 47 deletions(-) diff --git a/UnitsNet.Tests/BaseDimensionsTests.cs b/UnitsNet.Tests/BaseDimensionsTests.cs index c033c260e6..36dda28392 100644 --- a/UnitsNet.Tests/BaseDimensionsTests.cs +++ b/UnitsNet.Tests/BaseDimensionsTests.cs @@ -74,7 +74,7 @@ public void IsBaseQuantity_ForAcceleration_ReturnsFalse() { Assert.False(Acceleration.BaseDimensions.IsBaseQuantity()); } - + [Theory] [InlineData(2, 0, 0, 0, 0, 0, 0)] [InlineData(0, 2, 0, 0, 0, 0, 0)] @@ -733,13 +733,13 @@ public void CheckBaseDimensionMultiplicationWithForceEqualsMassTimesAcceleration [Fact] public void CheckToStringUsingMolarEntropy() { - Assert.Equal("[Length]^2[Mass][Time]^-2[Temperature]^-1[Amount]^-1", MolarEntropy.BaseDimensions.ToString()); + Assert.Equal("[Length^2][Mass][Time^-2][Temperature^-1][Amount^-1]", MolarEntropy.BaseDimensions.ToString()); } [Fact] public void CheckToStringUsingSpeed() { - Assert.Equal("[Length][Time]^-1", Speed.BaseDimensions.ToString()); + Assert.Equal("[Length][Time^-1]", Speed.BaseDimensions.ToString()); } [Fact] @@ -782,5 +782,6 @@ public void IsDimensionlessMethodImplementedCorrectly() // Example case Assert.True(Level.BaseDimensions.IsDimensionless()); } + } } diff --git a/UnitsNet.Tests/BaseUnitsTests.cs b/UnitsNet.Tests/BaseUnitsTests.cs index bf4d75f1cd..fc43e0e895 100644 --- a/UnitsNet.Tests/BaseUnitsTests.cs +++ b/UnitsNet.Tests/BaseUnitsTests.cs @@ -140,16 +140,21 @@ public void ToStringGivesExpectedResult() AmountOfSubstanceUnit.Mole, LuminousIntensityUnit.Candela); - UnitAbbreviationsCache cache = UnitsNetSetup.Default.UnitAbbreviations; - var m = cache.GetDefaultAbbreviation(LengthUnit.Meter); - var kg = cache.GetDefaultAbbreviation(MassUnit.Kilogram); - var s = cache.GetDefaultAbbreviation(DurationUnit.Second); - var A = cache.GetDefaultAbbreviation(ElectricCurrentUnit.Ampere); - var K = cache.GetDefaultAbbreviation(TemperatureUnit.Kelvin); - var mol = cache.GetDefaultAbbreviation(AmountOfSubstanceUnit.Mole); - var cd = cache.GetDefaultAbbreviation(LuminousIntensityUnit.Candela); - - Assert.Equal($"[Length]: {m}, [Mass]: {kg}, [Time]: {s}, [Current]: {A}, [Temperature]: {K}, [Amount]: {mol}, [LuminousIntensity]: {cd}", siBaseUnits.ToString()); + Assert.Equal("L=Meter, M=Kilogram, T=Second, I=Ampere, Θ=Kelvin, N=Mole, J=Candela", siBaseUnits.ToString()); + } + + [Fact] + public void ToString_WithFewerDimensions_ContainsOnlyTheSpecifiedDimensions() + { + var siBaseUnits = new BaseUnits(length:LengthUnit.Meter, mass:MassUnit.Gram, time:DurationUnit.Second, temperature:TemperatureUnit.DegreeCelsius); + + Assert.Equal("L=Meter, M=Gram, T=Second, Θ=DegreeCelsius", siBaseUnits.ToString()); + } + + [Fact] + public void ToString_WithUndefinedUnits_ReturnsUndefined() + { + Assert.Equal("Undefined", BaseUnits.Undefined.ToString()); } [Fact] diff --git a/UnitsNet/BaseDimensions.cs b/UnitsNet/BaseDimensions.cs index b229b21501..ec79f133ad 100644 --- a/UnitsNet/BaseDimensions.cs +++ b/UnitsNet/BaseDimensions.cs @@ -3,7 +3,6 @@ using System; using System.Text; -using System.Linq; namespace UnitsNet { @@ -30,9 +29,13 @@ public BaseDimensions(int length, int mass, int time, int current, int temperatu /// True if the dimensions represent a base quantity, otherwise false. public bool IsBaseQuantity() { - var dimensionsArray = new[] { Length, Mass, Time, Current, Temperature, Amount, LuminousIntensity }; - bool onlyOneEqualsOne = dimensionsArray.Select(dimension => dimension is 0 or 1 ? dimension : 2).Sum() == 1; - return onlyOneEqualsOne; + return (Length == 1 && Mass == 0 && Time == 0 && Current == 0 && Temperature == 0 && Amount == 0 && LuminousIntensity == 0) || + (Length == 0 && Mass == 1 && Time == 0 && Current == 0 && Temperature == 0 && Amount == 0 && LuminousIntensity == 0) || + (Length == 0 && Mass == 0 && Time == 1 && Current == 0 && Temperature == 0 && Amount == 0 && LuminousIntensity == 0) || + (Length == 0 && Mass == 0 && Time == 0 && Current == 1 && Temperature == 0 && Amount == 0 && LuminousIntensity == 0) || + (Length == 0 && Mass == 0 && Time == 0 && Current == 0 && Temperature == 1 && Amount == 0 && LuminousIntensity == 0) || + (Length == 0 && Mass == 0 && Time == 0 && Current == 0 && Temperature == 0 && Amount == 1 && LuminousIntensity == 0) || + (Length == 0 && Mass == 0 && Time == 0 && Current == 0 && Temperature == 0 && Amount == 0 && LuminousIntensity == 1); } /// @@ -71,7 +74,11 @@ public override bool Equals(object? obj) /// public override int GetHashCode() { - return new {Length, Mass, Time, Current, Temperature, Amount, LuminousIntensity}.GetHashCode(); +#if NET + return HashCode.Combine(Length, Mass, Time, Current, Temperature, Amount, LuminousIntensity); +#else + return new { Length, Mass, Time, Current, Temperature, Amount, LuminousIntensity }.GetHashCode(); +#endif } /// @@ -182,12 +189,16 @@ public override string ToString() private static void AppendDimensionString(StringBuilder sb, string name, int value) { - if (0 != value) + switch (value) { - sb.AppendFormat("[{0}]", name); - - if (1 != value) - sb.AppendFormat("^{0}", value); + case 0: + return; + case 1: + sb.AppendFormat("[{0}]", name); + break; + default: + sb.AppendFormat("[{0}^{1}]", name, value); + break; } } diff --git a/UnitsNet/BaseUnits.cs b/UnitsNet/BaseUnits.cs index 9b4b0bc59f..5f16a8fc08 100644 --- a/UnitsNet/BaseUnits.cs +++ b/UnitsNet/BaseUnits.cs @@ -2,7 +2,7 @@ // Copyright 2013 Andreas Gullberg Larsen (andreas.larsen84@gmail.com). Maintained at https://github.com/angularsen/UnitsNet. using System; -using System.Text; +using System.Collections.Generic; using UnitsNet.Units; namespace UnitsNet @@ -103,11 +103,11 @@ public bool IsSubsetOf(BaseUnits other) /// public override int GetHashCode() { -#if NET + #if NET return HashCode.Combine(Length, Mass, Time, Current, Temperature, Amount, LuminousIntensity); -#else + #else return new {Length, Mass, Time, Current, Temperature, Amount, LuminousIntensity}.GetHashCode(); -#endif + #endif } /// @@ -133,31 +133,47 @@ public override int GetHashCode() { return !(left == right); } - + /// public override string ToString() { - if(!Equals(Undefined)) + if (Equals(Undefined)) { - var sb = new StringBuilder(); - - string GetDefaultAbbreviation(TUnitType? unitOrNull) where TUnitType : struct, Enum => unitOrNull is { } unit - ? UnitsNetSetup.Default.UnitAbbreviations.GetDefaultAbbreviation(unit) - : "N/A"; + return "Undefined"; + } - sb.AppendFormat("[Length]: {0}, ", GetDefaultAbbreviation(Length)); - sb.AppendFormat("[Mass]: {0}, ", GetDefaultAbbreviation(Mass)); - sb.AppendFormat("[Time]: {0}, ", GetDefaultAbbreviation(Time)); - sb.AppendFormat("[Current]: {0}, ", GetDefaultAbbreviation(Current)); - sb.AppendFormat("[Temperature]: {0}, ", GetDefaultAbbreviation(Temperature)); - sb.AppendFormat("[Amount]: {0}, ", GetDefaultAbbreviation(Amount)); - sb.AppendFormat("[LuminousIntensity]: {0}", GetDefaultAbbreviation(LuminousIntensity)); + return string.Join(", ", GetUnitsDefined()); - return sb.ToString(); - } - else + IEnumerable GetUnitsDefined() { - return "Undefined"; + if (Length is not null) + { + yield return $"L={Length}"; + } + if (Mass is not null) + { + yield return $"M={Mass}"; + } + if (Time is not null) + { + yield return $"T={Time}"; + } + if (Current is not null) + { + yield return $"I={Current}"; + } + if (Temperature is not null) + { + yield return $"Θ={Temperature}"; + } + if (Amount is not null) + { + yield return $"N={Amount}"; + } + if (LuminousIntensity is not null) + { + yield return $"J={LuminousIntensity}"; + } } } @@ -200,8 +216,8 @@ string GetDefaultAbbreviation(TUnitType? unitOrNull) where TUnitType /// Gets a value indicating whether all base units are defined. /// /// - /// This property returns true if all seven base units - /// (Length, Mass, Time, Current, Temperature, Amount, and LuminousIntensity) + /// This property returns true if all seven base units + /// (Length, Mass, Time, Current, Temperature, Amount, and LuminousIntensity) /// are non-null; otherwise, it returns false. /// public bool IsFullyDefined => Length is not null &&