Introduction
This article is about UnitConversionLib, an open source library for conversion of units, arithmetic operation and parsing quantities with their units on run time. In this article, codes are provided in C#. you can download the library from Codeplex by going to this link. And clicking on the download button on the right side of the page.
Link and Download
UnitConversionLib
is an Open Source library available at Codeplex:
For downloading it, go to the link above and click on the 'download' button (colored with violet) in the right side of page and you should receive the .dll file.
Background
I am a civil engineer and when I was a student, I was involved with many values and formulas, one in metric system and other one in other system! So several years ago, I tried to create a library in .NET which let the user to be able to consider the units of values easily and lets the machine do the heavy job.
The idea of creating the UnitConversionLib
is:
- Letting users to be able to use the Visual Studio (any version, including Express) environment and C# code for parsing and arithmetic operations between quantities.
- Letting users to change and work with Units of Measurement in .NET in runtime.
As its coder, I do not guarantee the accuracy and validity of the library and the library like many other Opensource Libraries is 'AS IS'!
Next, I’m going to show you to how to use the library and a brief information about the library.
*Note: You may encounter some spelling errors in the library code at Codeplex, sorry for them!
Units of Measurement
There is a struct
named UnitConversionLib.Unit
which holds information about a unit of measurement. Basically there are two types of Units, ‘Base Units’ and ‘Derived Units’:
- Base Units, are units that are not derived from any unit. For example, in SI there are 5 base units that all other units are derived from:
- Meter
- Kilogram
- Second
- Ampere
- Kelvin
- Mol
- Candela
- Derived Units, are units that are derived from base units, all units in SI except 5 base units are derived from the 5 base units. There are several examples:
*Note: Derived units are not implemented as derived classes in UnitConversionLib
.
All SI base units (except Kelvin, check the Note in Consistent Units section) and some derived SI units are predefined in the library and you can check the list from the wiki page of UnitConversionLib on Codeplex.
Creating Base Units
Although the SI base units are pretty comprehensive, but sometimes there is a need for creating new base units. Unlike some other unit conversion libraries, the base units are not hard coded in UnitConversionLib
and the user is able to create them on the fly! For example, we want to create a ‘Bit’ base unit:
Unit bit = Unit.CreateNew("b");
You have to pass the name of unit to Unit.CreateNew()
method for identifying the name for library. This name will be used for parsing the Units from string
.
Creating Derived Units
For example, we want to create a byte unit which is derived from bit:
Unit B = bit * 8;
As you can see the ‘*’ and ‘/’ operators are overloaded for Unit
class.
After creating the unit
, you can register a name for it to be used in parsing unit
s from string
.
Unit.Register(ref B, "B");
For example, we have registered the byte unit with uppercase ‘B
’ and we will be able to parse this unit like either of these methods:
Unit unt0 = Unit.GetRegisteredUnit("B");
Unit unt1 = Unit.Parse("B");
Unit unt2 = "B";
In this case unt0
, unt1
and unt2
are equal. As equality operators (== and !=) are overloaded for Unit class, you can check the equality of units with == operator:
Debug.Assert(unt0 == unt1 && unt1 == unt2 && unt2 == unt3);
We also will create ‘KB
’ and ‘MB
’ which are equals to 1024 B and 1024 KB.
Unit KB = B * 1024;
Unit.Register(ref KB, "KB");
Unit MB = KB * 1024;
Unit.Register(ref MB, "MB");
Once we’ve registered new Units KB and MB, we will be able to use them. For example, creating units ‘bps’ (Bit Per Second), ‘Bps’ (Byte Per Second) and ‘KBps’ (KiloByte per second) is shown in several ways in the next snippet.
var bps = Unit.Parse("b") / Unit.Parse("sec");
Unit.Register(ref bps, "bps");
var Bps = Unit.Parse("B/sec");
Unit.Register(ref Bps, "Bps");
var KBps = "KB" / Unit.Parse("sec");
Unit.Register(ref KBps, "KBps");
Consistent Units
There are units who are pointing to the same origin, best example is Gram and Kilogram that both are units of mass or N (Newton) and Kgf (Kilogram force) which are units of force. These types of Units are consistent and are convertible to each other with a constant coefficient, for example Kilogram=1000.0*Gram or 1Gram=0.001 Kg.
In UnitConversionLib
, consistent units are convertible to each other and you can check it with Unit.IsConvertibleTo()
method. If returned value is true
, then units are convertible to each other with second double parameter which is specified with the out
keyword (out
keyword means that parameter value will set by method after executed). For example, snippet will check the consistency of Kilogram (Kg) and gram (gr) (while we know Gr*0.001=kg):
Debug.Assert(Unit.Parse("kg").IsConvertibleTo("gm", out coefficient));
Debug.Assert(coefficient==0.001);
*Note: 'Kelvin' and 'Fahrenheit' and 'Celsius' cannot be converted to each other in UnitConversionLib
because they are not consistent in UnitConversionLib
as they are not a constant coefficients of each other (unlike, for example, Kg and Gr which 1000*Gr=Kg)
Measuring Quantities
Every measurable quantity consists of a Value (magnitude) and an Unit. UnitConversionLib.Measurable struct
is used to represent a quantity that have both Unit
and Magnitude
. Like UnitConversionLib.Unit struct
, several operators are overloaded for this Measurable
objects, here is the list of operators and a brief information on each:
Arithmetic Operator | Applicable Types | Description |
* | Measurable*Measurable | Multiplying two measurables |
* | Measurable*double | Multiplying a measurable with a constant |
^ | Measurable^double | Raising a measurable object to specified power |
/ | Measurable/Measurable | Division of two measurables |
/ | Measurable/double | Division of measurable with a double |
/ | double/Measurable | Division of double with a measurable |
+ | Measurable+Measurable | Addition of two measurable (Units of Two Measurable should be consistent) |
== | Measurable==Measurable | Determining that are two measurable objects represents equal quantities |
!= | Measurable!=Measurable | Determining that are two measurable objects represents equal quantities |
This is an example of multiply and dividing Measurable
objects, for example a car has gone through a 100 m distance in 10 second, the average speed of car will be 100 m / 10 sec = 10 m/sec:
var D = Measurable.Parse("100 m");
var T = Measurable.Parse("10 sec");
var V = D/T;
Console.WriteLine("{0:0.0}",V);
Useful Code Snippets
In this snippet, several ways for parsing and working with units in UnitConversionLib
exist:
Unit unt0 = Unit.GetRegisteredUnit("N");
Unit unt1 = Unit.Parse("N");
Unit unt2 = "N";
Unit unt3 = Unit.Parse("kg*m/sec^2");
Unit unt4 = Unit.Parse("kg*m/s^(ton/kg/500)");
Unit unt5 = Unit.Parse("kg*m/s^(kg/kg*2)");
Unit unt6 = Unit.Parse("kg*m") / (Unit.Parse("sec") ^ 2);
Unit kg = Unit.Parse("kg");
Unit m = Unit.Parse("m");
Unit sec = Unit.Parse("sec");
Unit unt7 = kg * m / (sec ^ 2);
Debug.Assert(unt0 == unt1 && unt1 == unt2 && unt2 == unt3 &&
unt3 == unt4 && unt4 == unt5 && unt5 == unt6 && unt6 == unt7);
Unit unt8 = Unit.Parse("kg*m/s^(kg)");
Measurable meu0 = Measurable.Parse("100 N");
Measurable meu1 = "100 N";
Measurable meu2 = new Measurable(unt0, 100);
Debug.Assert(meu0 == meu1);
Measurable meu3 = meu0.ConvertTo("kgf");
Debug.Assert(meu3.Amount == 1000);
Debug.Assert(meu3.Unit == "kgf");
Measurable deltax = "100 m";
Measurable deltaT = "10 sec";
Measurable scUnit = "2 kg/kg";
Measurable avgAccl = deltax / (deltaT ^ scUnit);
Debug.Assert(avgAccl.Amount == 1);
Debug.Assert(avgAccl.Unit == "m/ sec^2");
Unit bit = Unit.CreateNew("b");
Unit B = bit * 8;
Unit.Register(ref B, "B");
Unit KB = B * 1024;
Unit.Register(ref KB, "KB");
Unit MB = KB * 1024;
Unit.Register(ref MB, "MB");
Unit GB = MB * 1024;
Unit.Register(ref GB, "GB");
Unit TB = GB * 1024;
Unit.Register(ref TB, "TB");
Unit bps = bit / Unit.GetRegisteredUnit("sec");
Unit.Register(ref bps, "bps");
Measurable smb = "100 MB/sec";
Measurable sb = smb.ConvertTo("bps");
Debug.Assert(sb.Amount == 838860800);
Debug.Assert(sb.Unit == bit / "sec");
Constants
There is also a static
class named UnitConversionLib.Consts
which holds some useful coefficients:
public static class Consts
{
public static readonly double Yotta = 1e+24;
public static readonly double Zetta = 1e+21;
public static readonly double Exa = 1e+18;
public static readonly double Peta = 1e+15;
public static readonly double Terra = 1e+12;
public static readonly double Giga = 1e+9;
public static readonly double Mega = 1e+6;
public static readonly double Kilo = 1e+3;
public static readonly double Hecto = 1e+2;
public static readonly double Deca = 1e+1;
public static readonly double Deci = 1e-1;
public static readonly double Centi = 1e-2;
public static readonly double Milli = 1e-3;
public static readonly double Micro = 1e-6;
public static readonly double Nano = 1e-9;
public static readonly double Pico = 1e-12;
public static readonly double Femto = 1e-15;
public static readonly double Atto = 1e-18;
public static readonly double Zeppto = 1e-21;
public static readonly double Yocto = 1e-24;
}
You can use UnitConversionLib.Consts
class like this:
Unit km = Unit.Parse("m") * Consts.Kilo;
Exceptions
Not all errors are throwing appropriated Exception in UnitConversionLib
and it needs more time to fix the code. However, there is a UnitConversionLibException
class and a UnitParsingException
that will be thrown in errors (but not all of them) with appropriated message (accessible from Exception.Message
property).
Conclusion
This article is about how to use open source library ‘UnitConversionLib
’ which stands for working with measurable quantities and unit conversion in .NET. You can download it from Codeplex with going to this link. And clicking on the download button on the right side of the page.
History
- 18th June, 2014: Initial version