用于多种单位转换的 C# 数据结构

发布于 2024-07-12 10:36:09 字数 231 浏览 9 评论 0原文

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

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

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

有什么建议么?

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

I have a C# app and I need to convert between 3 different units (say for example: litres, gallons, and pints).

The app needs to know about certain volumes of liquid, say: 1 pint, 10 pints, 20 pints and 100 pints. I intend to do the calculations and hard code the values (not ideal but necessary),

I'm looking for a data structure that will allow me to easily convert from one unit to another.

Any suggestions?

Please note: I'm not actually using volumes of liquid, its just an example!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

只是我以为 2024-07-19 10:36:09

您可以存储转换系数矩阵,其中

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

You can store a matrix of conversion factors where

  • a: Is litres
  • b: Is pints
  • c: Are gallons

You'd have (not accurate, but assuming there are two pints to a litre and 4 litres to a gallon)

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

Alternatively, you can decide that everything is converted to a base value (litres) before being converted to another type, then you just need the first line.

Wrap this in a method that takes a number of units and "from" type and "two" type for the conversion.

Hope this helps

EDIT: some code, as requested

    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
    }
当梦初醒 2024-07-19 10:36:09

我通过提供正确的访问方法(属性)用另一种语言完成了此操作:

for the class Volume:
  AsLitre
  AsGallon
  AsPint

for the class Distance:
  AsInch
  AsMeter
  AsYard
  AsMile

另一个优点是内部格式并不重要。

I have done this in an other language by providing the correct access methods (properties):

for the class Volume:
  AsLitre
  AsGallon
  AsPint

for the class Distance:
  AsInch
  AsMeter
  AsYard
  AsMile

One additional advantage is that the internal format does not matter.

堇色安年 2024-07-19 10:36:09

请查看显式接口实现,我认为它可以帮助你,样本就是你所需要的。

编辑:从 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());
   }
}

Please take a look at Explicit Interface Implementation, I think it can help you, the sample is about what you need.

EDIT: sample copied from 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());
   }
}
心奴独伤 2024-07-19 10:36:09

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

UnitConversion on:

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

In case it is helpfull, you might want to use a nuget package that's doing conversions between various units:

UnitConversion on:

Full disclosure: I'm currently maintaining this package.

情场扛把子 2024-07-19 10:36:09

以下是完整的源代码:

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 厘格勒。

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

Here's the source code in its full entirety:

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

It processes the file in the following format

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

and calculates, for instance, 50 centiglobs in decaglobs.

This code is capable of doing chained conversions (e.g. year -> day -> hour -> second).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文