【问题标题】:C# data structure for multiple unit conversions用于多单位转换的 C# 数据结构
【发布时间】:2010-10-04 10:51:09
【问题描述】:

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

应用需要了解特定体积的液体,例如:1 品脱、10 品脱、20 品脱和 100 品脱。我打算进行计算并对值进行硬编码(不理想但必要),

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

有什么建议吗?

请注意:我实际上并没有使用大量的液体,这只是一个例子!

【问题讨论】:

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


    【解决方案1】:

    如果有帮助,您可能需要使用 nuget 包来进行各种单位之间的转换:

    单位转换开启:

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

    【讨论】:

      【解决方案2】:

      您可以将转换因子矩阵存储在哪里

      • 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
          }
      

      【讨论】:

      • 我喜欢使用矩阵的想法。您能否详细说明在当前情况下将如何实施? TIA。
      【解决方案3】:

      这是完整的源代码:

      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
      

      并计算例如 50 centiglobs in decaglobs。

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

      【讨论】:

        【解决方案4】:

        请看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());
           }
        }
        

        【讨论】:

          【解决方案5】:

          我通过提供正确的访问方法(属性)以另一种语言完成了这项工作:

          for the class Volume:
            AsLitre
            AsGallon
            AsPint
          
          for the class Distance:
            AsInch
            AsMeter
            AsYard
            AsMile
          

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-10-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-02
            • 2017-03-31
            • 1970-01-01
            相关资源
            最近更新 更多