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
NOTE: This is work in progress and early thoughts, but input is most welcome.
An interface or abstract type implemented by all quantity types, such as Length and Mass.
Motivation
Represent generic quantities in code, where we don't need to know if it is Length or Mass but want to communicate it is a quantity - we need to use object today
Get textual representation of quantity with someQuantity.ToString() => "5 kg", this works today except we need to treat it as object and we don't have access to overloads for things like culture and significant digits after radix
Enumerate units for this quantity as this currently requires reflection, a usecase is to dynamically show GUI for converting a passed in quantity (1 meter) to any of the other length units
Present generic quantities visually in a 2D graph by showing unit selector for the quantities to change unit and getting the values for each quantity in the selected unit, without hardcoding support for specific quantities
Discussion points
Should we change quantities from struct to class? As discussed in the double/decimal issue, with class we might benefit from supporting both double and decimal internal representations without doubling the code. With an interface, it will quickly be boxed anyway unless using generic methods instead
Should the new members be added to quantity base type or be added to the UnitSystem type. One thing to consider is what culture to use for things like abbreviations and number formatting, where UnitSystem instances are created explicitly with a given culture (default uses CurrentUICulture in Windows).
Proposal
Add interface IQuantity since structs can't inherit base types, but users should be wary that casting to interface means boxing the value with those performance implications
ToString() should reflect the original value and unit instead of using the base unit, which may be very different than the units the user is working with (addressed in Preserve value and unit #389)
Add getter property for QuantityType since quantities already expose this value
Add getter properties for original value and unit to present or filter on these values separately
Add getter property for unit abbreviations as current you must figure out to use UnitSystem.Default.GetAllAbbreviations()
Add getter properties for singular and plural names of quantity for both "ForcePerLength" and "Force per length" forms, to make it easier to textually describe the quantity type. Currently you use reflection to obtain QuantityType enum value and call ToString() on it to get "ForcePerLength".
Add methods to obtain singular and plural names of a given unit to get `"Newton
Add getter property for the quantity description in JSON so this can be displayed next to the quantity selector GUI
Add getter property for enumerating all units for this QuantityType as this currently requires reflection (see sample app https://github.com/angularsen/UnitsNet/pull/380/files#diff-6f7804b386e2c6cd78fb5a331e9c9a58R18)
-UnitConverter.ConvertBy methods should not use reflection as this is unnecessary brittle and can be solved by generating code to check if from/to unit types are LengthUnit and passing that to Length.From() and Length.As() methods
Reduce code size by moving shared code into base type (or helper class), we currently have ~80 quantities. We already do use helper classes for heavy things like Parse() and ToString(), so not sure how much more to gain here.
Case studies
Converter app with hard coded quantities and using strings for conversions
Since quantities are hard coded in the app, we can obtain the list of units like this:
if (selectedQuantity == "Length") { SetConversionUnits(Length.Units.Select(x => x.ToString())) }
else if (selectedQuantity == "Mass") {} /* and so on */
Alternative is to use reflection to obtain list of units, but this is brittle
Use strings for quantities and units in the GUI lists and use UnitConverter to convert between two units of a quantity like this:
The main difference to the example above is that we want to obtain the list of units for any selected quantity, without knowing the quantity type.
We either have the quantity string ("Length" or "Mass"), or its equivalent QuantityType.Length and QuantityType.Mass enum values, but there is currently no intuitive way of getting abbreviations from this.
Challenge: Present the plural name of any unit
For listing units in the GUI. We can get "meter" and "newton per meter" from LengthUnit.Meter and ForcePerLengthUnit.NewtonPerMeter by calling ToString() and splitting the pascal case into lower case words, but it would only be singular and difficult to reliably present in plural form. The plural form is defined in JSON, so we can easily generate that.
Challenge: Present abbreviation of any unit
This currently requires you to know the quantity or unit type, in order to look it up statically via string x = Length.GetAbbreviation(LengthUnit unit) or dynamically via string x = UnitSystem.Default.GetDefaultAbbreviation(Type unitType, int unitValue)
This dotnetfiddle shows how to get all length abbreviations, given that we added LengthUnit values to the list and can resolve abbreviations based on that type:
object[] lengthUnits = Length.Units.Skip(1).Take(10).Cast<object>().ToArray(); // Assume we add these to the GUI list and read those back as `object`s at some point
Console.WriteLine("Length unit abbreviations: " + string.Join(", ", lengthUnits.Select(unit => UnitSystem.Default.GetDefaultAbbreviation(unit.GetType(), (int)unit))));
// Output:
// Length unit abbreviations: cm, dm, pica, pt, fathom, ft, in, km, m, µin
A base type could have the method `GetAbbreviation(object unit)
Discussion on converting from struct to class to support decimal#285
This is related, because we are here discussing whether to convert from struct to class in order to get the benefit of supporting both double and decimal in the same library without doubling the code size.
NOTE: This is work in progress and early thoughts, but input is most welcome.
An interface or abstract type implemented by all quantity types, such as
LengthandMass.Motivation
LengthorMassbut want to communicate it is a quantity - we need to useobjecttodaysomeQuantity.ToString()=>"5 kg", this works today except we need to treat it asobjectand we don't have access to overloads for things like culture and significant digits after radixDiscussion points
UnitSystemtype. One thing to consider is what culture to use for things like abbreviations and number formatting, whereUnitSysteminstances are created explicitly with a given culture (default uses CurrentUICulture in Windows).Proposal
IQuantitysince structs can't inherit base types, but users should be wary that casting to interface means boxing the value with those performance implicationsQuantityTypesince quantities already expose this valueUnitSystem.Default.GetAllAbbreviations()"ForcePerLength"and"Force per length"forms, to make it easier to textually describe the quantity type. Currently you use reflection to obtainQuantityTypeenum value and callToString()on it to get"ForcePerLength".QuantityTypeas this currently requires reflection (see sample app https://github.com/angularsen/UnitsNet/pull/380/files#diff-6f7804b386e2c6cd78fb5a331e9c9a58R18)-UnitConverter.ConvertBy methods should not use reflection as this is unnecessary brittle and can be solved by generating code to check if from/to unit types are LengthUnit and passing that to
Length.From()andLength.As()methodsParse()andToString(), so not sure how much more to gain here.Case studies
Converter app with hard coded quantities and using strings for conversions
https://github.com/angularsen/UnitsNet#example-creating-a-unit-converter-app
UnitConverterto convert between two units of a quantity like this:Converter app with generic quantities #353
The main difference to the example above is that we want to obtain the list of units for any selected quantity, without knowing the quantity type.
We either have the quantity string (
"Length"or"Mass"), or its equivalentQuantityType.LengthandQuantityType.Massenum values, but there is currently no intuitive way of getting abbreviations from this.Challenge: Present the plural name of any unit
For listing units in the GUI. We can get "meter" and
"newton per meter"fromLengthUnit.MeterandForcePerLengthUnit.NewtonPerMeterby callingToString()and splitting the pascal case into lower case words, but it would only be singular and difficult to reliably present in plural form. The plural form is defined in JSON, so we can easily generate that.Challenge: Present abbreviation of any unit
This currently requires you to know the quantity or unit type, in order to look it up statically via
string x = Length.GetAbbreviation(LengthUnit unit)or dynamically viastring x = UnitSystem.Default.GetDefaultAbbreviation(Type unitType, int unitValue)This dotnetfiddle shows how to get all length abbreviations, given that we added
LengthUnitvalues to the list and can resolve abbreviations based on that type:https://dotnetfiddle.net/9f5TiF
A base type could have the method `GetAbbreviation(object unit)
Discussion on converting from
structtoclassto supportdecimal#285This is related, because we are here discussing whether to convert from
structtoclassin order to get the benefit of supporting bothdoubleanddecimalin the same library without doubling the code size.Fixes #354
Related issues