Strongly-typed units and measurements for .NET with deterministic dimensional algebra and canonical reduction. Safe arithmetic over Measurement<T>, SI ↔ Imperial conversions, decimal prefixes and powers, and affine-aware temperatures.
$ dotnet add package Veggerby.UnitsStrongly-typed units and measurements for .NET with deterministic dimensional algebra, reduction, and safe conversions across SI ↔ Imperial.
Measurement<T> with conversion helpersTargets .NET 9.0.
dotnet add package Veggerby.Units
using Veggerby.Units;
using Veggerby.Units.Conversion;
// Units are canonical and order-independent
var u1 = (Unit.SI.m * Unit.SI.s) ^ 2; // (m*s)^2
var u2 = (Unit.SI.m ^ 2) * (Unit.SI.s ^ 2);
bool equal = (u1 == u2); // true
// Measurements retain their unit and enforce dimension integrity
var a = new DoubleMeasurement(2.0, Unit.SI.m);
var b = new DoubleMeasurement(3.0, Unit.SI.m);
var sum = a + b; // 5 m
// Conversions are explicit
var oneMeter = new DoubleMeasurement(1.0, Unit.SI.m);
var inFeet = oneMeter.ConvertTo(Unit.Imperial.ft); // ~3.28084 ft
// Illegal operations throw
// var bad = a + new DoubleMeasurement(1.0, Unit.SI.s); // throws UnitException
A*B == B*A, division is negative exponents, and powers distribute where beneficial.var m = Unit.SI.m; // metre
var s = Unit.SI.s; // second
var ft = Unit.Imperial.ft; // foot
var speed = m / s; // m/s
var accel = m / (s ^ 2); // m/s^2
var area = m ^ 2; // m^2
// Decimal prefixes (exact powers of ten only)
var km = 1000 * m; // k·m (kilometre)
var mm = Prefix.m * m; // milli·metre
// Canonical equality
(Unit.Multiply(m, s) == (s * m)); // true
((m * s) ^ 2 == (m ^ 2) * (s ^ 2)); // true
Notes:
PrefixException.UnitException.var d1 = new DoubleMeasurement(2.5, Unit.SI.m);
var d2 = new DoubleMeasurement(1.5, Unit.SI.m);
var d3 = d1 + d2; // 4.0 m
// Different units must be converted before +/-
var m1 = new DoubleMeasurement(1.0, Unit.SI.m);
var f1 = new DoubleMeasurement(1.0, Unit.Imperial.ft);
var f1InMeters = f1.ConvertTo(Unit.SI.m);
var d4 = m1 + f1InMeters; // ok
// Relational comparisons align units on the right to the left
bool less = m1 < f1; // compares as m1 < f1.ConvertTo(m1.Unit)
// Unit composition via measurements
var t = new DoubleMeasurement(10.0, Unit.SI.s);
var distance = new DoubleMeasurement(20.0, Unit.SI.m);
var speed = distance / t; // 2 m/s
Use ConvertTo for explicit conversions or TryConvertTo to avoid exceptions.
using Veggerby.Units.Conversion;
var tempC = Temperature.Celsius(25.0); // 25 °C
var tempF = tempC.ConvertTo(Unit.Imperial.F); // 77 °F
DoubleMeasurement result;
bool ok = tempF.TryConvertTo(Unit.SI.C, out result); // true
MeasurementConversionException in ConvertTo and return false in TryConvertTo.var c = Temperature.Celsius(20);
var f = c.ConvertTo(Unit.Imperial.F); // 68 °F
// Illegal – throws UnitException:
// var x = Unit.SI.C * Unit.SI.m; // ❌
// var y = 1000 * Unit.SI.C; // ❌
MIT License — see the repository LICENSE file.
Questions or ideas? Open an issue at veggerby/Veggerby.Units.