Using real world units instead of types
我有一个项目,有很多计算涉及很多实际单位:
- 距离;
- 温度;
- 流量;
- …
本工程计算公式复杂、多。
这就是为什么我要使用自定义类型,如温度、距离…对代码可读性很好。例如:
1 2 | Temperature x = -55.3; Meter y = 3; |
或
1 |
号
我尝试创建一个使用双内部值的温度类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class Temperature { double _Value = double.NaN; public Temperature() { } public Temperature(double v) { _Value = v; } public static implicit operator Temperature(double v) { return new Temperature(v); } } |
但是类可以为空。这意味着:
1 | Temperature myTemp; |
。
是"正确的",将为空。我不想要这个。我不想使用结构,因为它们太有限:
- 它们不能使用无参数构造函数或实例字段初始化器(如
double _Value = double.Nan; 来定义默认值(i将默认的基础双值指定为NaN) - 它们不能从类继承,只能实现接口
我想知道是否有办法告诉C:
1 | Temperature myTemp = 23K; // C# does not implement anything to make K unit... |
但我知道C不处理任何自定义单位。
1 |
。
所以我想我可以创建两个从温度继承的摄氏度和开尔文类,然后我开始怀疑这个想法是否真的值得,因为它涉及很多编码和测试。
这就是我想开始的讨论:
在我的代码中使用真实世界单位而不是.NET类型是否是一件好事?已经有人这么做了吗?什么是陷阱和最佳实践?或者我应该远离这些,使用标准的.NET类型吗?
为什么不尝试这样的结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /// <summary> /// Temperature class that uses a base unit of Celsius /// </summary> public struct Temp { public static Temp FromCelsius(double value) { return new Temp(value); } public static Temp FromFahrenheit(double value) { return new Temp((value - 32) * 5 / 9); } public static Temp FromKelvin(double value) { return new Temp(value - 273.15); } public static Temp operator +(Temp left, Temp right) { return Temp.FromCelsius(left.Celsius + right.Celsius); } private double _value; private Temp(double value) { _value = value; } public double Kelvin { get { return _value + 273.15; } } public double Celsius { get { return _value; } } public double Fahrenheit { get { return _value / 5 * 9 + 32; } } } |
然后像这样使用它,比如说:
1 2 3 4 5 6 7 8 9 | static void Main(string[] args) { var c = Temp.FromCelsius(30); var f = Temp.FromFahrenheit(20); var k = Temp.FromKelvin(20); var total = c + f + k; Console.WriteLine("Total temp is {0}F", total.Fahrenheit); } |
。
实现这一点的一种方法是使用基本对象的组合(在您的例子中是
在您的案例中,您可以定义一个
江户十一〔11〕。
然后,实现不仅取决于可度量类,还取决于单位类。这在实践中有多有用取决于这种对象中有多少是真正通用的——在
如果这种方法看起来有趣的话,这里有一篇关于C特性的研究论文。
我会把
派生类
比较它们(一个比另一个暖和)会很容易。
我认为不值得为C中的单元添加静态类型。您需要过载这么多的操作符(对于所有单元组合,而不仅仅是对于所有单元)。以及内置函数,比如math.sqrt在普通双精度上工作,…
您可以尝试使用动态类型:
1 2 3 4 5 6 7 8 9 | class PhysicalUnit { } struct PhysicalValue { readonly Value; readonly PhysicalUnit; } |
号
然后在调试模式下编译时,添加检查单元是否匹配。在发行版中,只需去掉physicalunit字段和所有的检查,您(几乎)和使用普通双精度代码的速度一样快。
如果使用结构,则不能是EDOCX1[2]
1 2 3 4 | struct Temperature { double _Value; } |
我认为当你想在一个温度上增加更具体的功能时(例如:
用开尔文和摄氏度来解决这个问题:创建一个接口