65.9K
CodeProject 正在变化。 阅读更多。
Home

UnitConversionLib:C# 中的智能单位转换库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (8投票s)

2014 年 6 月 17 日

CPOL

6分钟阅读

viewsIcon

48730

关于如何在 C# 中使用 UnitConversionLib 进行单位和数量转换的信息

引言

本文介绍 UnitConversionLib,这是一个开源库,用于在运行时转换单位、进行算术运算以及解析带单位的数量。本文中的代码是用 C# 编写的。您可以通过访问 此链接 从 Codeplex 下载该库。然后在页面右侧点击下载按钮。

链接和下载

UnitConversionLib 是一个在 Codeplex 上提供的开源库

要下载它,请访问上面的链接,然后点击页面右侧的(紫色的)“下载”按钮,您应该会收到一个 .dll 文件。

背景

我是一名土木工程师,在学生时代,我经常接触许多数值和公式,有些是公制单位,有些是其他单位!因此,几年前,我尝试在 .NET 中创建一个库,让用户能够轻松地考虑数值的单位,并让机器完成繁重的工作。

创建 UnitConversionLib 的想法是

  • 让用户能够使用 Visual Studio(任何版本,包括 Express 版)环境和 C# 代码来解析数量并进行算术运算。
  • 让用户在运行时能够更改和处理 .NET 中的 计量单位

作为其开发者,我不保证该库的准确性和有效性,该库与其他许多开源库一样,是“按原样”提供的!

接下来,我将向您展示如何使用该库以及关于该库的简要信息。

*注意:您可能会在 Codeplex 的库代码中遇到一些拼写错误,对此表示歉意!

计量单位

有一个名为 UnitConversionLib.Unitstruct,它保存有关计量单位的信息。基本上,单位有两种类型:“基本单位”和“导出单位”。

  • 基本单位是指不派生自任何其他单位的单位。例如,在 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 中解析 units。

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!

在这种情况下,unt0unt1unt2 是相等的。由于 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 用于表示一个同时具有 UnitMagnitude 的数量。与 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.Constsstatic 类,它包含一些有用的系数。

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 日:初始版本
© . All rights reserved.