使用真实世界单位而不是类型

Lar*_*rry 10 c# types units-of-measurement

我有一个涉及许多现实世界单位的许多计算项目:

  • 距离;
  • 温度;
  • 流量;
  • ...

该项目涉及复杂而众多的计算公式.

这就是为什么我认为使用像Temperature,Distance ...... 这样的自定义类型可以提高代码的可读性.例如:

Temperature x = -55.3;
Meter y = 3;
Run Code Online (Sandbox Code Playgroud)

要么

var x = new Temperature(-55.3);
Run Code Online (Sandbox Code Playgroud)

我试图制作一个使用双内部值的Temperature类.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是类可以为空.这意味着:

Temperature myTemp;
Run Code Online (Sandbox Code Playgroud)

是"正确的",将为空.我不想要这个.我不想使用结构,因为它们太有限了:

  • 他们不能使用无参数构造函数或实例字段初始化器double _Value = double.Nan;来定义默认值(我的默认底层double值为NaN)
  • 它们不能从类继承,它们只能实现接口

我想知道是否有办法告诉C#:

Temperature myTemp = 23K; // C# does not implement anything to make K unit...
Run Code Online (Sandbox Code Playgroud)

但我知道C#不处理任何自定义单位.

Temperature myTemp = new Kelvin(23); // This might work
Run Code Online (Sandbox Code Playgroud)

所以我想我可以创建两个继承温度的Celsius和Kelvin类,然后我开始怀疑这个想法是否真的值得,因为它涉及大量的编码和测试.

这是我想要开始的讨论:

在我的代码中使用真实世界单元而不是.NET类型是否是一件好事?有人这个吗?有哪些陷阱和最佳做法?或者我应该更好地远离这个并使用标准的.NET类型?

OJ.*_*OJ. 10

为什么不尝试看起来像这样的结构:

/// <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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它,比如说:

    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);
    }
Run Code Online (Sandbox Code Playgroud)


Ste*_*end 1

实现此目的的一种方法是将基本对象(Temperature在您的情况下)与TemperatureTraits专用于基本对象的类结合使用。与 C++ 类比,String等效类basic_string实际上是一个类模板(C# 术语中的泛型),它不仅具有字符串元素(char宽字符)的模板参数,而且还具有一个特征类,该特征类详细说明了该类对于给定类型的行为方式字符串元素(例如char_traits)。

在你的情况下,你可以定义一个通用的,比如

public class MeasurableWithUnits<class M MEASURABLE, class U UNITS>

那么实施不仅取决于可测量的类别,还取决于单位类别。这在实践中有多有用取决于有多少这样的对象可以真正通用——哪些操作在Measurable和 的组合中是常见的Units

如果这种方法看起来有趣的话,这里有一篇关于 C# 特征的研究论文。