多个单位转换的C#数据结构

时间:2009-01-30 10:45:53

标签: c# data-structures units-of-measurement

我有一个C#应用程序,我需要在3个不同的单位之间进行转换(例如:升,加仑和品脱)。

应用程序需要知道某些体积的液体,比如:1品脱,10品脱,20品脱和100品脱。我打算进行计算并对值进行硬编码(不理想但必要),

我正在寻找一种数据结构,可以让我轻松地从一个单位转换为另一个单位。

有什么建议吗?

请注意:我不是实际使用大量液体,这只是一个例子!

5 个答案:

答案 0 :(得分:7)

您可以存储转换因子矩阵

  • a:升是
  • b:是品脱
  • c:加仑

你有(不准确,但假设有一品脱到一升和4升到一加仑)

   a     b       c
a  1     2     0.25
b  0.5   1     0.125
c  4     8       1

或者,您可以在转换为其他类型之前决定将所有内容转换为基本值(升),然后您只需要第一行。

将此包装在一个方法中,该方法需要多个单位,“from”类型和“two”类型才能进行转换。

希望这有帮助

编辑:部分代码,按要求

    public enum VolumeType
    {
        Litre = 0,
        Pint = 1,
        Gallon = 2
    }

    public static double ConvertUnits(int units, VolumeType from, VolumeType to)
    {
        double[][] factor = 
            {
                new double[] {1, 2, 0.25},
                new double[] {0.5, 1, 0.125},
                new double[] {4, 8, 1}
            };
        return units * factor[(int)from][(int)to];
    }

    public static void ShowConversion(int oldUnits, VolumeType from, VolumeType to)
    {
        double newUnits = ConvertUnits(oldUnits, from, to);
        Console.WriteLine("{0} {1} = {2} {3}", oldUnits, from.ToString(), newUnits, to.ToString());
    }


    static void Main(string[] args)
    {
        ShowConversion(1, VolumeType.Litre, VolumeType.Litre);  // = 1
        ShowConversion(1, VolumeType.Litre, VolumeType.Pint);   // = 2
        ShowConversion(1, VolumeType.Litre, VolumeType.Gallon); // = 4
        ShowConversion(1, VolumeType.Pint, VolumeType.Pint);    // = 1
        ShowConversion(1, VolumeType.Pint, VolumeType.Litre);   // = 0.5
        ShowConversion(1, VolumeType.Pint, VolumeType.Gallon);  // = 0.125
        ShowConversion(1, VolumeType.Gallon, VolumeType.Gallon);// = 1
        ShowConversion(1, VolumeType.Gallon, VolumeType.Pint);  // = 8
        ShowConversion(1, VolumeType.Gallon, VolumeType.Litre); // = 4
        ShowConversion(10, VolumeType.Litre, VolumeType.Pint);  // = 20
        ShowConversion(20, VolumeType.Gallon, VolumeType.Pint); // = 160
    }

答案 1 :(得分:5)

我通过提供正确的访问方法(属性)以其他语言完成此操作:

for the class Volume:
  AsLitre
  AsGallon
  AsPint

for the class Distance:
  AsInch
  AsMeter
  AsYard
  AsMile

另一个优点是内部格式无关紧要。

答案 2 :(得分:2)

请看一下Explicit Interface Implementation,我认为它可以帮到你,样本就是你需要的。

编辑:从MSDN复制的样本

interface IEnglishDimensions 
{
   float Length();
   float Width();
}
// Declare the metric units interface:
interface IMetricDimensions 
{
   float Length();
   float Width();
}
// Declare the "Box" class that implements the two interfaces:
// IEnglishDimensions and IMetricDimensions:
class Box : IEnglishDimensions, IMetricDimensions 
{
   float lengthInches;
   float widthInches;
   public Box(float length, float width) 
   {
      lengthInches = length;
      widthInches = width;
   }
// Explicitly implement the members of IEnglishDimensions:
   float IEnglishDimensions.Length() 
   {
      return lengthInches;
   }
   float IEnglishDimensions.Width() 
   {
      return widthInches;      
   }
// Explicitly implement the members of IMetricDimensions:
   float IMetricDimensions.Length() 
   {
      return lengthInches * 2.54f;
   }
   float IMetricDimensions.Width() 
   {
      return widthInches * 2.54f;
   }
   public static void Main() 
   {
      // Declare a class instance "myBox":
      Box myBox = new Box(30.0f, 20.0f);
      // Declare an instance of the English units interface:
      IEnglishDimensions eDimensions = (IEnglishDimensions) myBox;
      // Declare an instance of the metric units interface:
      IMetricDimensions mDimensions = (IMetricDimensions) myBox;
      // Print dimensions in English units:
      System.Console.WriteLine("Length(in): {0}", eDimensions.Length());
      System.Console.WriteLine("Width (in): {0}", eDimensions.Width());
      // Print dimensions in metric units:
      System.Console.WriteLine("Length(cm): {0}", mDimensions.Length());
      System.Console.WriteLine("Width (cm): {0}", mDimensions.Width());
   }
}

答案 3 :(得分:1)

如果它有用,您可能想要使用在不同单位之间进行转换的nuget包:

UnitConversion on:

完全披露:我目前正在维护这个包。

答案 4 :(得分:0)

以下是完整的源代码:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;

namespace UnitConversion
{
    internal delegate double Converter(double value);

    class UnitConverter
    {
        private readonly IDictionary<string, IDictionary<string, Converter>> converters =
            new Dictionary<string, IDictionary<string, Converter>>();
        private readonly NumberFormatInfo numberFormatInfo;

        public UnitConverter()
        {
            numberFormatInfo = (NumberFormatInfo)NumberFormatInfo.InvariantInfo.Clone();
            numberFormatInfo.NumberDecimalSeparator = ".";
            numberFormatInfo.NumberGroupSeparator = String.Empty;
        }

        public void ParseConverterDefinition(string converterDefinition)
        {
            string[] parts = converterDefinition.Split(' ');
            double sourceUnitsValue = double.Parse(parts[0], NumberFormatInfo.InvariantInfo);
            double targetUnitsValue = double.Parse(parts[3], NumberFormatInfo.InvariantInfo);

            AddConverters(parts[1], sourceUnitsValue, parts[4], targetUnitsValue);
            AddConverters(parts[4], targetUnitsValue, parts[1], sourceUnitsValue);
        }

        private void AddConverters(string sourceUnits, double sourceUnitsValue, string targetUnits, double targetUnitsValue)
        {
            if (!converters.ContainsKey(sourceUnits))
                converters.Add(sourceUnits, new Dictionary<string, Converter>());

            converters[sourceUnits][targetUnits] =
                delegate(double value)
                { return value * targetUnitsValue / sourceUnitsValue; };
        }

        public double? Convert(double value, string sourceUnits, string targetUnits, params string[] skipUnits)
        {
            if (!converters.ContainsKey(sourceUnits))
                return null;

            if (converters[sourceUnits].ContainsKey(targetUnits))
                return converters[sourceUnits][targetUnits](value);

            foreach (KeyValuePair<string, Converter> pair in converters[sourceUnits])
            {
                if (Array.IndexOf(skipUnits, pair.Key) != -1)
                    continue;

                List<string> skip = new List<string>(skipUnits);
                skip.Add(sourceUnits);

                double? result = Convert(converters[sourceUnits][pair.Key](value), pair.Key, targetUnits, skip.ToArray());
                if (result != null)
                    return result;
            } // foreach

            return null;
        }

        public string Convert(string conversionRequest)
        {
            string[] parts = conversionRequest.Split(' ');
            return ConvertFormatted(double.Parse(parts[0], NumberFormatInfo.InvariantInfo), parts[1], parts[4]);
        }

        public string ConvertFormatted(double value, string sourceUnits, string targetUnits)
        {
            double? convertedValue = Convert(value, sourceUnits, targetUnits);
            if (convertedValue == null)
                return "No conversion is possible.";

            return string.Format("{0} {1} = {2} {3}", value.ToString("N6", numberFormatInfo), sourceUnits,
                convertedValue < 0.01 || convertedValue > 1000000 ?
                    convertedValue.Value.ToString("#.######e+00", numberFormatInfo) :
                    convertedValue.Value.ToString("N6", numberFormatInfo),
                targetUnits);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {

            UnitConverter unitConverter = new UnitConverter();

            foreach (string s in File.ReadAllLines("Conversions.txt"))
            {
                if (s.IndexOf("?") == -1)
                    unitConverter.ParseConverterDefinition(s);
                else
                    Console.WriteLine(unitConverter.Convert(s));
            } // foreach
        }
    }
}

它以下列格式处理文件

7200.0 second = 2 hour
10.0 glob = 1 decaglob
1 day = 24.0 hour
1 minute = 60 second
1 glob = 10 centiglob
1 day = 24 hour
1 year = 365.25 day
50 centiglob = ? decaglob
5.6 second = ? hour
3 millisecond = ? hour
5.6 second = ? day
1 day = ? glob
1 hour = ? second
1 year = ? second
例如,计算出decaglobs中的50个centiglobs。

此代码能够进行链式转换(例如年 - >天 - >小时 - >秒>。