Skip to content

Commit 090742c

Browse files
authored
Adding the missing BaseUnits (#1473)
Fixes #1463 Fixes #1043 - removed the `UnitSystem` constructor from the Dimensionless quantities (which was previously throwing) - `As`/`ToUnit(UnitSystem)` for all dimensionless quantities now convert to their `BaseUnit` (i.e. the "DecimalFraction") * - `As/ToUnit(UnitSystem)` for all other quantities refactored using the QuantityInfoExtensions - added tests for the `UnitSystem` methods, skipping the tests for all quantities that fail with `UnitSystem.SI` (with a reason) There are only two dimensionless quantities (IMO) that don't fit the definition: - `RelativeHumidity`: currently has only the `Percent` unit, I think we should add the `DecimalFraction`, setting it to be the `BaseUnit` - `FuelEfficiency`: I think this could be defined as `"L": -2` with the addition of the `MeterPerCubicMeter` unit (possibly setting it as its `BaseUnit`, if we want to satisfy the `BaseUnit_HasSIBase` test) You can look for `As_UnitSystem_ReturnsValueInDimensionlessUnit` if you want to check the rest of the dimensionless quantities. Regarding the removed `BaseUnits` (see `Force.json` or `Pressure.json`), those were detected by some earlier tests I had in place, regarding the multiplication/division operators where I used the following definition: - A given operation between two quantities (either multiplication or division) such as `A / B = C` is only defined if `A.Dimensions / B.Dimensions = C.Dimensions` - When the intersection between `A.Dimensions` and `B.Dimensions` is the empty set, for every unit of `A` and `B` for which the `BaseUnits` is not `Unidefined`, and every unit of `C`, having `BaseUnits` = `A.BaseUnits union B.BaseUnits`, it must be true that `C.Value = A.Value / B.Value`. - When the intersection between `A.Dimensions` and `B.Dimensions` is not empty, and the intersecting `BaseUnits` of `A` , `B` and `C` are all the same, then again we have the same condition, which I generally refer to as "the conversion coefficient is 1" - The same logic can be used to infer the unit-conversion coefficient based off the `Dimensions` and a pair of `BaseUnits`, but special attention needs to be taken w.r.t. the exponents (e.g. `Area` is `L2` so the unit-conversion coefficients are squares of the ones from `Length`) - If we want to extend this definition in the future, we should consider introducing a way to override the "default conversion coefficient" (`1`).. Here are some links: https://en.wikipedia.org/wiki/Dimensional_analysis https://en.wikipedia.org/wiki/International_System_of_Units#Definition https://en.wikipedia.org/wiki/Coherence_(units_of_measurement)
1 parent cdab29e commit 090742c

File tree

341 files changed

+17113
-8234
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

341 files changed

+17113
-8234
lines changed

CodeGen/Generators/UnitsNetGen/QuantityGenerator.cs

Lines changed: 30 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,10 @@ private void GenerateInstanceConstructors()
214214
Writer.WL($@"
215215
_unit = unit;
216216
}}
217-
217+
");
218+
if (!_isDimensionless)
219+
{
220+
Writer.WL($@"
218221
/// <summary>
219222
/// Creates an instance of the quantity with the given numeric value in units compatible with the given <see cref=""UnitSystem""/>.
220223
/// If multiple compatible units were found, the first match is used.
@@ -225,18 +228,11 @@ private void GenerateInstanceConstructors()
225228
/// <exception cref=""ArgumentException"">No unit was found for the given <see cref=""UnitSystem""/>.</exception>
226229
public {_quantity.Name}(double value, UnitSystem unitSystem)
227230
{{
228-
if (unitSystem is null) throw new ArgumentNullException(nameof(unitSystem));
229-
230-
var unitInfos = Info.GetUnitInfosFor(unitSystem.BaseUnits);
231-
var firstUnitInfo = unitInfos.FirstOrDefault();
232-
");
233-
234-
Writer.WL(@"
235-
_value = value;");
236-
Writer.WL($@"
237-
_unit = firstUnitInfo?.Value ?? throw new ArgumentException(""No units were found for the given UnitSystem."", nameof(unitSystem));
231+
_value = value;
232+
_unit = Info.GetDefaultUnit(unitSystem);
238233
}}
239234
");
235+
}
240236
}
241237

242238
private void GenerateStaticProperties()
@@ -1000,34 +996,16 @@ public double As({_unitEnumName} unit)
1000996
}}
1001997
");
1002998

1003-
Writer.WL($@"
999+
Writer.WL( $@"
10041000
10051001
/// <inheritdoc cref=""IQuantity.As(UnitSystem)""/>
10061002
public double As(UnitSystem unitSystem)
10071003
{{
1008-
if (unitSystem is null)
1009-
throw new ArgumentNullException(nameof(unitSystem));
1010-
1011-
var unitInfos = Info.GetUnitInfosFor(unitSystem.BaseUnits);
1012-
1013-
var firstUnitInfo = unitInfos.FirstOrDefault();
1014-
if (firstUnitInfo == null)
1015-
throw new ArgumentException(""No units were found for the given UnitSystem."", nameof(unitSystem));
1016-
1017-
return As(firstUnitInfo.Value);
1004+
return As(Info.GetDefaultUnit(unitSystem));
10181005
}}
10191006
");
10201007

10211008
Writer.WL($@"
1022-
/// <inheritdoc />
1023-
double IQuantity.As(Enum unit)
1024-
{{
1025-
if (!(unit is {_unitEnumName} typedUnit))
1026-
throw new ArgumentException($""The given unit is of type {{unit.GetType()}}. Only {{typeof({_unitEnumName})}} is supported."", nameof(unit));
1027-
1028-
return As(typedUnit);
1029-
}}
1030-
10311009
/// <summary>
10321010
/// Converts this {_quantity.Name} to another {_quantity.Name} with the unit representation <paramref name=""unit"" />.
10331011
/// </summary>
@@ -1123,29 +1101,33 @@ private bool TryToUnit({_unitEnumName} unit, [NotNullWhen(true)] out {_quantity.
11231101
converted = convertedOrNull.Value;
11241102
return true;
11251103
}}
1104+
");
1105+
Writer.WL($@"
1106+
/// <inheritdoc cref=""IQuantity.ToUnit(UnitSystem)""/>
1107+
public {_quantity.Name} ToUnit(UnitSystem unitSystem)
1108+
{{
1109+
return ToUnit(Info.GetDefaultUnit(unitSystem));
1110+
}}
1111+
");
11261112

1127-
/// <inheritdoc />
1128-
IQuantity IQuantity.ToUnit(Enum unit)
1113+
Writer.WL($@"
1114+
#region Explicit implementations
1115+
1116+
double IQuantity.As(Enum unit)
11291117
{{
1130-
if (!(unit is {_unitEnumName} typedUnit))
1118+
if (unit is not {_unitEnumName} typedUnit)
11311119
throw new ArgumentException($""The given unit is of type {{unit.GetType()}}. Only {{typeof({_unitEnumName})}} is supported."", nameof(unit));
11321120
1133-
return ToUnit(typedUnit, DefaultConversionFunctions);
1121+
return As(typedUnit);
11341122
}}
11351123
1136-
/// <inheritdoc cref=""IQuantity.ToUnit(UnitSystem)""/>
1137-
public {_quantity.Name} ToUnit(UnitSystem unitSystem)
1124+
/// <inheritdoc />
1125+
IQuantity IQuantity.ToUnit(Enum unit)
11381126
{{
1139-
if (unitSystem is null)
1140-
throw new ArgumentNullException(nameof(unitSystem));
1141-
1142-
var unitInfos = Info.GetUnitInfosFor(unitSystem.BaseUnits);
1143-
1144-
var firstUnitInfo = unitInfos.FirstOrDefault();
1145-
if (firstUnitInfo == null)
1146-
throw new ArgumentException(""No units were found for the given UnitSystem."", nameof(unitSystem));
1127+
if (!(unit is {_unitEnumName} typedUnit))
1128+
throw new ArgumentException($""The given unit is of type {{unit.GetType()}}. Only {{typeof({_unitEnumName})}} is supported."", nameof(unit));
11471129
1148-
return ToUnit(firstUnitInfo.Value);
1130+
return ToUnit(typedUnit, DefaultConversionFunctions);
11491131
}}
11501132
11511133
/// <inheritdoc />
@@ -1158,6 +1140,8 @@ IQuantity IQuantity.ToUnit(Enum unit)
11581140
IQuantity<{_unitEnumName}> IQuantity<{_unitEnumName}>.ToUnit(UnitSystem unitSystem) => ToUnit(unitSystem);
11591141
11601142
#endregion
1143+
1144+
#endregion
11611145
");
11621146
}
11631147

0 commit comments

Comments
 (0)