UnitConversionLib:C# 中的智能单位转换库
关于如何在 C# 中使用 UnitConversionLib 进行单位和数量转换的信息
引言
本文介绍 UnitConversionLib,这是一个开源库,用于在运行时转换单位、进行算术运算以及解析带单位的数量。本文中的代码是用 C# 编写的。您可以通过访问 此链接 从 Codeplex 下载该库。然后在页面右侧点击下载按钮。
链接和下载
UnitConversionLib
是一个在 Codeplex 上提供的开源库
要下载它,请访问上面的链接,然后点击页面右侧的(紫色的)“下载”按钮,您应该会收到一个 .dll 文件。
背景
我是一名土木工程师,在学生时代,我经常接触许多数值和公式,有些是公制单位,有些是其他单位!因此,几年前,我尝试在 .NET 中创建一个库,让用户能够轻松地考虑数值的单位,并让机器完成繁重的工作。
创建 UnitConversionLib
的想法是
- 让用户能够使用 Visual Studio(任何版本,包括 Express 版)环境和 C# 代码来解析数量并进行算术运算。
- 让用户在运行时能够更改和处理 .NET 中的 计量单位。
作为其开发者,我不保证该库的准确性和有效性,该库与其他许多开源库一样,是“按原样”提供的!
接下来,我将向您展示如何使用该库以及关于该库的简要信息。
*注意:您可能会在 Codeplex 的库代码中遇到一些拼写错误,对此表示歉意!
计量单位
有一个名为 UnitConversionLib.Unit
的 struct
,它保存有关计量单位的信息。基本上,单位有两种类型:“基本单位”和“导出单位”。
- 基本单位是指不派生自任何其他单位的单位。例如,在 SI 制中,有 5 个基本单位,所有其他单位都派生自它们。
- 米
- 千克
- 第二种
- 安培
- 开尔文
- 摩尔
- 坎德拉
- 导出单位是指派生自基本单位的单位。在 SI 制中,除 5 个基本单位外,所有单位都派生自这 5 个基本单位。这里有一些例子。
- N=kg·m/s2
- Hz=1/s
*注意:在 UnitConversionLib
中,导出单位不实现为派生类。
库中预定义了所有 SI 基本单位(开尔文除外,请参阅 “一致单位”部分的注释)和一些 SI 导出单位。您可以从 Codeplex 上 UnitConversionLib 的 wiki 页面 查看列表。
创建基本单位
尽管 SI 基本单位相当全面,但有时需要创建新的基本单位。与一些其他单位转换库不同,基本单位在 UnitConversionLib
中不是硬编码的,用户可以即时创建它们!例如,我们想创建一个“比特”基本单位。
Unit bit = Unit.CreateNew("b");//Create a new fundamental unit
您必须将单位的名称传递给 Unit.CreateNew()
方法,以供库识别。此名称将用于从 string
中解析单位。
创建导出单位
例如,我们想创建一个派生自比特的字节单位。
Unit B = bit * 8;
如您所见,Unit
类 重载了 “*” 和 “/” 运算符。
创建 unit
后,您可以为其注册一个名称,以便从 string
中解析 unit
s。
Unit.Register(ref B, "B");
例如,我们已将字节单位注册为大写“B
”,并且我们可以通过以下任一方法解析此单位:
Unit unt0 = Unit.GetRegisteredUnit("B");//method 1: From registered library
Unit unt1 = Unit.Parse("B");//method 2: Parsing from string - simple format
Unit unt2 = "B";//method 3: <a href="http://msdn.microsoft.com/en-us/library/z5z9kes2.aspx">Implicit conversion!
在这种情况下,unt0
、unt1
和 unt2
是相等的。由于 Unit 类重载了相等运算符(== 和 !=),您可以使用 == 运算符检查单位的相等性。
Debug.Assert(unt0 == unt1 && unt1 == unt2 && unt2 == unt3);
我们还将创建“KB
”和“MB
”,它们分别等于 1024 B 和 1024 KB。
Unit KB = B * 1024;
Unit.Register(ref KB, "KB");
Unit MB = KB * 1024;
Unit.Register(ref MB, "MB");
一旦我们注册了新的 Units KB 和 MB,我们就可以使用它们了。例如,下面的代码片段展示了创建单位“bps”(比特每秒)、“Bps”(字节每秒)和“KBps”(千字节每秒)的几种方法。
var bps = Unit.Parse("b") / Unit.Parse("sec");//using .Parse() method
Unit.Register(ref bps, "bps");
var Bps = Unit.Parse("B/sec");// Parsing complex unit from string
Unit.Register(ref Bps, "Bps");
var KBps = "KB" / Unit.Parse("sec");//using implicit conversion from string to unit
Unit.Register(ref KBps, "KBps");
一致单位
有些单位指向同一个来源,最好的例子是克和千克,它们都是质量单位,或者 N(牛顿)和 Kgf(千克力),它们都是力的单位。这些类型的单位是一致的,并且可以用一个恒定的系数相互转换,例如 千克 = 1000.0 * 克,或 1 克 = 0.001 千克。
在 UnitConversionLib
中,一致单位可以相互转换,您可以使用 Unit.IsConvertibleTo()
方法进行检查。如果返回值是 true
,则单位可以相互转换,转换系数通过第二个双精度参数给出,该参数使用 out
关键字指定(out
关键字表示方法执行后将设置参数值)。例如,下面的代码片段将检查千克 (Kg) 和克 (gr) 的一致性(尽管我们知道 Gr * 0.001 = kg)。
Debug.Assert(Unit.Parse("kg").IsConvertibleTo("gm", out coefficient));
Debug.Assert(coefficient==0.001);
*注意:在 UnitConversionLib
中,“开尔文”、“华氏度和摄氏度”之间无法相互转换,因为它们在 UnitConversionLib
中不一致,它们之间不存在恒定的系数(不像例如,千克和克,其中 1000 * 克 = 千克)。
测量数量
每个可测量数量都由一个值(数量级)和一个 Unit
组成。UnitConversionLib.Measurable struct
用于表示一个同时具有 Unit
和 Magnitude
的数量。与 UnitConversionLib.Unit struct
一样,Measurable
对象也重载了多个运算符,下面是运算符列表以及每个运算符的简要说明:
算术运算符 | 适用类型 | 描述 |
* | Measurable * Measurable | 两个可测量数相乘 |
* | Measurable * double | 可测量数乘以一个常数 |
^ | Measurable ^ double | 将可测量对象提升到指定幂 |
/ | Measurable / Measurable | 两个可测量数相除 |
/ | Measurable / double | 可测量数除以一个双精度数 |
/ | double / Measurable | 双精度数除以一个可测量数 |
+ | Measurable + Measurable | 两个可测量数相加(两个可测量数的单位必须一致) |
== | Measurable == Measurable | 确定两个可测量对象是否表示相等数量 |
!= | Measurable != Measurable | 确定两个可测量对象是否表示相等数量 |
这是一个乘法和除法 Measurable
对象的示例,例如,汽车在 10 秒内行驶了 100 米的距离,汽车的平均速度将是 100 米 / 10 秒 = 10 米/秒。
var D = Measurable.Parse("100 m");
var T = Measurable.Parse("10 sec");
var V = D/T;
Console.WriteLine("{0:0.0}",V); // will show 10.0 m/sec
有用的代码片段
在这个片段中,存在几种在 UnitConversionLib
中解析和处理单位的方法。
//Creating and parsing units
Unit unt0 = Unit.GetRegisteredUnit("N");//From registered library
Unit unt1 = Unit.Parse("N");//Parsing from string - simple format
Unit unt2 = "N";//Implicit conversion
Unit unt3 = Unit.Parse("kg*m/sec^2");//Parsing from string - from expression (1)
Unit unt4 = Unit.Parse("kg*m/s^(ton/kg/500)");//Parsing from string - from expression (2)
Unit unt5 = Unit.Parse("kg*m/s^(kg/kg*2)");//Parsing from string - from expression (3)
Unit unt6 = Unit.Parse("kg*m") / (Unit.Parse("sec") ^ 2);//Parsing from string - from expression (4)
Unit kg = Unit.Parse("kg");
Unit m = Unit.Parse("m");
Unit sec = Unit.Parse("sec");
Unit unt7 = kg * m / (sec ^ 2);//Evaluating through runtime
Debug.Assert(unt0 == unt1 && unt1 == unt2 && unt2 == unt3 &&
unt3 == unt4 && unt4 == unt5 && unt5 == unt6 && unt6 == unt7);
Unit unt8 = Unit.Parse("kg*m/s^(kg)");//will raise error, a unit cannot be placed in power
//In Action I:
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");
//In action II, calculating average acceleration
Measurable deltax = "100 m";
Measurable deltaT = "10 sec";
Measurable scUnit = "2 kg/kg";
Measurable avgAccl = deltax / (deltaT ^ scUnit);//which is 1 m/sec^2
Debug.Assert(avgAccl.Amount == 1);
Debug.Assert(avgAccl.Unit == "m/ sec^2");
//In action III: creating new units
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");// 100 MB = 100*1024*1024*8 b = 838860800 b
Debug.Assert(sb.Amount == 838860800);
Debug.Assert(sb.Unit == bit / "sec");
常量
还有一个名为 UnitConversionLib.Consts
的 static
类,它包含一些有用的系数。
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;
}
您可以这样使用 UnitConversionLib.Consts
类:
Unit km = Unit.Parse("m") * Consts.Kilo;
异常
并非所有错误都会在 UnitConversionLib
中抛出适当的异常,修复代码还需要更多时间。但是,有一个 UnitConversionLibException
类和一个 UnitParsingException
,它们将在发生错误时(但并非所有错误)抛出,并附带适当的消息(可通过 Exception.Message
属性访问)。
结论
本文介绍了如何使用开源库“UnitConversionLib
”,该库用于在 .NET 中处理可测量数量和单位转换。您可以通过访问 此链接 从 Codeplex 下载它。然后点击页面右侧的下载按钮。
历史
- 2014 年 6 月 18 日:初始版本