Skip to content

Extending with Custom Units

Andreas Gullberg Larsen edited this page Oct 14, 2020 · 20 revisions

If you are looking to add new quantities or units to the official UnitsNet nuget, please see https://github.com/angularsen/UnitsNet/wiki/Adding-a-New-Unit.

Units.NET structure

Units.NET roughly consists of these parts:

  • Quantities like Length and Force
  • Unit enum values like LengthUnit.Meter and ForceUnit.Newton
  • UnitAbbreviationsCache, UnitParser, QuantityParser and UnitConverter for parsing and converting quantities and units
  • JSON files for defining units, conversion functions and abbreviations
  • CodeGen.exe to generate C# code based on JSON files

Example: Custom quantity HowMuch with units HowMuchUnit

Sample output

GetDefaultAbbreviation(): sm, lts, tns
Parse<HowMuchUnit>(): Some, Lots, Tons

Convert 10 tons to:
200 sm
100 lts
10 tns

Map unit enum values to unit abbreviations

// Map enum values to abbreviations
UnitAbbreviationsCache.Default.MapUnitToDefaultAbbreviation(HowMuchUnit.Some, "sm");
UnitAbbreviationsCache.Default.MapUnitToDefaultAbbreviation(HowMuchUnit.Lots, "lts");
UnitAbbreviationsCache.Default.MapUnitToDefaultAbbreviation(HowMuchUnit.Tons, "tns");

Lookup unit abbrevations from enum values

Console.WriteLine("GetDefaultAbbreviation(): " + string.Join(", ", 
	UnitAbbreviationsCache.Default.GetDefaultAbbreviation(HowMuchUnit.Some), // "sm"
	UnitAbbreviationsCache.Default.GetDefaultAbbreviation(HowMuchUnit.Lots), // "lts"
	UnitAbbreviationsCache.Default.GetDefaultAbbreviation(HowMuchUnit.Tons)	 // "tns"
));

Parse unit abbreviations back to enum values

Console.WriteLine("Parse<HowMuchUnit>(): " + string.Join(", ",
	UnitParser.Default.Parse<HowMuchUnit>("sm"),  // Some
	UnitParser.Default.Parse<HowMuchUnit>("lts"), // Lots
	UnitParser.Default.Parse<HowMuchUnit>("tns")  // Tons
));

Convert between units of custom quantity

var unitConverter = UnitConverter.Default;
unitConverter.SetConversionFunction<HowMuch>(HowMuchUnit.Lots, HowMuchUnit.Some, x => new HowMuch(x.Value * 2, HowMuchUnit.Some));
unitConverter.SetConversionFunction<HowMuch>(HowMuchUnit.Tons, HowMuchUnit.Lots, x => new HowMuch(x.Value * 10, HowMuchUnit.Lots));
unitConverter.SetConversionFunction<HowMuch>(HowMuchUnit.Tons, HowMuchUnit.Some, x => new HowMuch(x.Value * 20, HowMuchUnit.Some));

var from = new HowMuch(10, HowMuchUnit.Tons);
var toUnits = new[] { HowMuchUnit.Some, HowMuchUnit.Lots, HowMuchUnit.Tons};
IQuantity Convert(HowMuchUnit toUnit) => unitConverter.GetConversionFunction<HowMuch>(from.Unit, toUnit)(from);

Console.WriteLine($"Convert 10 tons to:");
Console.WriteLine(Convert(HowMuchUnit.Some)); // 200 sm
Console.WriteLine(Convert(HowMuchUnit.Lots)); // 100 lts
Console.WriteLine(Convert(HowMuchUnit.Tons)); // 10 tns

Sample quantity

https://github.com/angularsen/UnitsNet/blob/master/UnitsNet.Tests/CustomQuantities/HowMuchUnit.cs
https://github.com/angularsen/UnitsNet/blob/master/UnitsNet.Tests/CustomQuantities/HowMuch.cs

public enum HowMuchUnit
{
	Some,
	Lots,
	Tons
}

public struct HowMuch : IQuantity
{
	public HowMuch(double value, HowMuchUnit unit)
	{
		Unit = unit;
		Value = value;
	}

	Enum IQuantity.Unit => Unit;
	public HowMuchUnit Unit { get; }

	public double Value { get; }

	#region IQuantity

	private static readonly HowMuch Zero = new HowMuch(0, HowMuchUnit.Some);

	public QuantityType Type => QuantityType.Undefined;
	public BaseDimensions Dimensions => BaseDimensions.Dimensionless;

	public QuantityInfo QuantityInfo => new QuantityInfo(Type,
		new UnitInfo[]
		{
				new UnitInfo<HowMuchUnit>(HowMuchUnit.Some, BaseUnits.Undefined),
				new UnitInfo<HowMuchUnit>(HowMuchUnit.Lots, BaseUnits.Undefined),
				new UnitInfo<HowMuchUnit>(HowMuchUnit.Tons, BaseUnits.Undefined),
		},
		HowMuchUnit.Some,
		Zero,
		BaseDimensions.Dimensionless);

	public double As(Enum unit) => Convert.ToDouble(unit);

	public double As(UnitSystem unitSystem) => throw new NotImplementedException();

	public IQuantity ToUnit(Enum unit)
	{
		if (unit is HowMuchUnit howMuchUnit) return new HowMuch(As(unit), howMuchUnit);
		throw new ArgumentException("Must be of type HowMuchUnit.", nameof(unit));
	}

	public IQuantity ToUnit(UnitSystem unitSystem) => throw new NotImplementedException();

	public override string ToString() => $"{Value} {UnitAbbreviationsCache.Default.GetDefaultAbbreviation(Unit)}";
	public string ToString(string format, IFormatProvider formatProvider) => $"HowMuch ({format}, {formatProvider})";
	public string ToString(IFormatProvider provider) => $"HowMuch ({provider})";
	public string ToString(IFormatProvider provider, int significantDigitsAfterRadix) => $"HowMuch ({provider}, {significantDigitsAfterRadix})";
	public string ToString(IFormatProvider provider, string format, params object[] args) => $"HowMuch ({provider}, {string.Join(", ", args)})";

	#endregion
}
Clone this wiki locally