You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Merge pull request #389 from angularsen/angularsen/preserve-value-unit
### Motivation
Preserve the original value and unit and add getter properties `Value` and `Unit` to expose them.
Use `Unit` in `ToString()` instead of the base unit representation, to better match the units the user is working with.
This is a significant rewrite of how values are stored and how conversions are performed in quantity types. It is also the first baby steps of introducing some common values in base types #371 .
**There should be no breaking changes in neither main lib nor JSON serialization.**
### Changes
Using example of `Length`, but this applies to all quantities:
- Change private field `_meters` to `_value` (still `double` or `decimal`, as before)
- Add private field `LengthUnit? _unit`
- Add `Value` getter prop (`double` or `decimal`)
- Add `LengthUnit Unit` getter prop, with fallback to base unit `LengthUnit.Meter` (1)
- Ctors without unit param assumes `BaseUnit`, backwards compatible
- Change `ToString()` to use `Unit` instead of `DefaultToStringUnit`, new test cases
- Mark `DefaultToStringUnit` as obsolete
- Add support for preserving `decimal` precision in `QuantityValue` (2)
- Defer conversion to base unit until calling properties like `.Centimeters` (3)
- Serialize `Value`+`Unit` instead of base unit and base unit value, backwards compatible, update test cases
- Make internals of UnitsNet visible to Json to reuse reflection abstraction code
- Rename variables in JSON serialization lib (use "quantity" term instead of "unit")
1) Default ctor (`struct`) and ctors without unit param assumes base unit, to be backwards compatible. We might want to change this in the future to require explicitly specifying the unit.
2) Needed to avoid precision issues going via double to construct decimal values.
3) Getting the value of unit properties is now twice as slow, as it first converts from `Unit` to base unit, then to target unit. Before this change, the first conversion was initially made when constructing the quantity. However, there are optimizations in-place to avoid converting if `Unit` already matches either base unit or the target unit.
### Gotchas
- Serialization output changed (different value and unit for same quantity)
- In #389 (comment) I discuss the choice to not go with breaking change with regards to unspecified unit, but why we may want to do so later to require explicitly specifying the unit
// We use this type that takes implicit cast from all number types to avoid explosion of method overloads that take a numeric value.
152
+
return(QuantityValue)value;
153
+
}
154
+
155
+
thrownewException(
156
+
$"The first parameter of the reflected quantity From() method was expected to be either UnitsNet.QuantityValue, but was instead {valueParameterType}.");
// TODO Should we serialize long, decimal and long differently?
210
+
Value=Convert.ToDouble(quantityValue),
211
+
Unit=quantityUnitName
212
+
});
213
+
}
214
+
215
+
/// <summary>
216
+
/// Given quantity (ex: <see cref="Mass"/>), returns the full name (ex: "MassUnit.Kilogram") of the constructed unit given by the <see cref="Mass.Unit"/> property.
217
+
/// </summary>
218
+
/// <param name="obj">Quantity, such as <see cref="Mass"/>.</param>
219
+
/// <param name="quantityType">The type of <paramref name="obj"/>, passed in here to reuse a previous lookup.</param>
220
+
/// <returns>"MassUnit.Kilogram" for a mass quantity whose Unit property is MassUnit.Kilogram.</returns>
0 commit comments