C# 单元转换器程序

C# 单元转换器程序,c#,wpf,units-of-measurement,C#,Wpf,Units Of Measurement,我正在为我的学期项目开发一个单元转换器。我需要一些关于类/接口/抽象类结构的帮助。我想要一些可以被类(DegreesConverter、MassConverter、LenghtConverter)继承的接口或抽象类。比如可能接口IUnitConvert。首先,我将讨论角度(度、弧度、梯度)、力(牛顿、帕斯卡)和数据(字节、KB、MB、GB、TB)的单位。有什么建议吗?有很多不同的方法可以解决这个问题。这里有一种使用代理的方法 public class Converter { public

我正在为我的学期项目开发一个单元转换器。我需要一些关于类/接口/抽象类结构的帮助。我想要一些可以被类(DegreesConverter、MassConverter、LenghtConverter)继承的接口或抽象类。比如可能
接口IUnitConvert
。首先,我将讨论角度(度、弧度、梯度)、力(牛顿、帕斯卡)和数据(字节、KB、MB、GB、TB)的单位。有什么建议吗?

有很多不同的方法可以解决这个问题。这里有一种使用代理的方法

public class Converter
{
    public static double Convert(double original, Func<double, double> conversion)
    {
        return conversion(original);
    }
}

public class SizeConverter
{
    public static double MegabytesToBytes(double megabytes)
    {
        return megabytes * 1048576;
    }

    public static double KilobytesToBytes(double kilobytes)
    {
        return kilobytes * 1024;
    }
}

如果您需要Double以外的其他类型,则需要重载Convert方法。

思考您希望如何使用它,并让它来指导您。例如,您希望表示哪种度量单位?你们的基本单位是什么?如何处理度量单位之间的转换

马上,我想我们可以看到,你需要一些方法来表示一个测量单位,例如英尺、米、升、弗隆、度、千克、磅、居里、欧姆等等,这看起来像是一个类,或者一系列的类——可能以单位为基,以英尺、米、升、弗隆为子类。然后我想你需要一些方法把一个单位和一个值联系起来。此单位/值必须提供某种方式在相同类型的度量单位(长度/距离、体积、温度、质量/重量)之间进行转换,并且如果调用代码尝试可疑的操作(例如将27摄氏度转换为英里/小时),该单位/值必须足够明亮,以引发合理的异常。一些创建单位/值实例的便捷方法会很方便。单位/价值的东西不应该与特定种类或类别的单位挂钩,而是应该能够愉快地处理你想扔给它的任何单位

代码方面,我认为这样的东西会很棒:

UnitValue a, b, c;

a = new UnitValue(3 * 5280, Feet);
b = new UnitValue(180, Seconds);
c = (a / b).As(Miles / Hours);
cout << c;
因此,您可以看到,将一个单位值除以另一个单位值应该会生成一个新的单位值和一个复合单位-在本例中,
a/b
应该生成一个单位值,单位为英尺/秒(英尺/秒),然后转换例程
As
将其转换为其他单位,在本例中为英里/小时

我希望这有助于激发你的思考


共享和享受。

首先想到的是类似System.TimeSpan的东西,其中相同的类表示时间,您可以通过属性以不同的单位访问它

您可以在内部以某种常量单位(大概是SI)存储该值,并将其转换为属性getter/setter:

Distance d = new Distance;
d.Meters = 5000;
var km = d.Kilometers; // km = 5;
或者,您可以为每个单元创建类:

public sealed class DistanceUnit
{
    public DistanceUnit(string name, string symbol, double scale)
    {
        Name = name;
        Symbol = symbol;
        Scale = scale;
    }

    public string Name { get; private set; }
    public string Symbol { get; private set; }
    public double Scale { get; private set; }
}


public abstract class Distance
{
    protected Distance(double value)
    {
        this.Value = value;
    }

    protected Distance()
    {
    }

    public double Value { get; set; }

    public abstract DistanceUnit Unit { get; }

    public override string ToString()
    {
        return this.Value + " " + Unit.Symbol;
    }


    public static void Convert<TIn, TOut>(TIn original, out TOut result)
        where TIn : Distance, new()
        where TOut : Distance, new()
    {

        result = new TOut();

        var scale = result.Unit.Scale / original.Unit.Scale;

        result.Value = original.Value * scale;
    }

}

public sealed class Meter : Distance
{

    private static readonly DistanceUnit s_Unit = new DistanceUnit("Meter", "m", 1);

    public Meter(double value) : base(value)
    {
    }

    public Meter()
    {
    }

    public override DistanceUnit Unit
    {
        get { return s_Unit; }

    }
}

public sealed class Kilometer : Distance
{
    private static readonly DistanceUnit s_Unit = new DistanceUnit("Kilometer", "km", .001);

    public Kilometer()
    {
    }

    public Kilometer(double value)
        : base(value)
    {
    }

    public override DistanceUnit Unit
    {
        get { return s_Unit; }
    }
}

到目前为止,您有什么问题?这种方法的唯一问题是,当您添加更多的单元时,SizeConverter枚举中会出现组合爆炸-BytesToKB?MBtoKB?如果我加入千兆字节,会发生什么?使用b/kb/mb/gb/tb将有20种方法用于所有可能的转换,对吗?我不认为这是不合理的,考虑到每个转换本质上是一行代码。你是对的,我不认为在类项目的范围内,这将是你必须担心的事情。我会使用相同的距离。转换方法吗?是的,这将是相同的距离(米,英尺英里,等等)的任何两个实现,你把它传给它。
Distance d = new Distance;
d.Meters = 5000;
var km = d.Kilometers; // km = 5;
public sealed class DistanceUnit
{
    public DistanceUnit(string name, string symbol, double scale)
    {
        Name = name;
        Symbol = symbol;
        Scale = scale;
    }

    public string Name { get; private set; }
    public string Symbol { get; private set; }
    public double Scale { get; private set; }
}


public abstract class Distance
{
    protected Distance(double value)
    {
        this.Value = value;
    }

    protected Distance()
    {
    }

    public double Value { get; set; }

    public abstract DistanceUnit Unit { get; }

    public override string ToString()
    {
        return this.Value + " " + Unit.Symbol;
    }


    public static void Convert<TIn, TOut>(TIn original, out TOut result)
        where TIn : Distance, new()
        where TOut : Distance, new()
    {

        result = new TOut();

        var scale = result.Unit.Scale / original.Unit.Scale;

        result.Value = original.Value * scale;
    }

}

public sealed class Meter : Distance
{

    private static readonly DistanceUnit s_Unit = new DistanceUnit("Meter", "m", 1);

    public Meter(double value) : base(value)
    {
    }

    public Meter()
    {
    }

    public override DistanceUnit Unit
    {
        get { return s_Unit; }

    }
}

public sealed class Kilometer : Distance
{
    private static readonly DistanceUnit s_Unit = new DistanceUnit("Kilometer", "km", .001);

    public Kilometer()
    {
    }

    public Kilometer(double value)
        : base(value)
    {
    }

    public override DistanceUnit Unit
    {
        get { return s_Unit; }
    }
}
Meter distanceHome = new Meter(10000);
Kilometer distanceInKMs;

Distance.Convert(distanceHome, out distanceInKMs);   //  distanceInKMs.Value = 10