使用枚举实现层次结构的最佳C#模式是什么?

时间:2010-10-20 07:15:35

标签: c# enums hierarchy

我正在实现代表距离(或长度)的值类型。 有一个枚举代表不同的度量单位,例如:

public enum DistanceUnit 
{
   Millimeter,
   Centimeter,
   Meter,
   Kilometer,
   Inch,
   Foot,
   Yard,
   Mile
};

这些测量属于两个系统之一 - 公制或英制。由于枚举不支持层次结构,表示这种层次结构的最佳模式是什么?

是否使用位标志? 或者使用两个单独的枚举以及一些方法来关联它们? 或者声明静态成员而不是枚举?

给我一​​些建议...... 将如何实现这个?


编辑 - 更多说明: 我有几个不可变的结构(由T4生成)代表各种测量:

public struct Meters : IEquatable<Distance>, 
                       IEquatable<Meters>, 
                       IEquatable<Millimeters>, ... IComparable<> etc.. etc..
{
    public readonly decimal Value;
    ...
    public static implicit operator Distance (Meters other) {
        // Can implicitly cast to Distance
    }
}

public struct Millimeters ...
public struct Centimeters ....

...等,以及手动编码的不可变距离,旨在表示任何度量:

public struct Distance : IEquatable<Distance>, 
                       IEquatable<Meters>, 
                       IEquatable<Millimeters>, ...
                       IFormattable
{

    public readonly decimal Value;
    public readonly DistanceUnits UnitOfMeasure;
    ...
    public string ToString(string format, IFormatProvider provider)
    {
        // Logic:
        // If UOM = Meters and Value < .1 then display as "10 cm" instead of ".1 M"
        // If UOM = Inches and value multiple of 12, display as feet
        // etc, etc
    }
}

在讨论是否应通过调用代码将距离转换为正确的UOM时,此处的目标是让ToString在当前UnitOfMeasure表示的相同度量(英制或公制)上向上或向下转换值

显然这可以全部硬编码到ToString方法中,但鉴于我也在为整个shibang实现TypeConverters和FormatProviders,我想找到一种通用方法,从DistanceUnit中找出什么,适当的下一个或下一个下降的计量单位将是。

我是不是想以这种方式实施错误的树?

3 个答案:

答案 0 :(得分:10)

你真的需要enum吗?也许,一个简单的value object会做什么?

public class Distance
{
    private readonly decimal millimeters;

    public decimal Meters
    { 
        get { return millimeters * 0.001m; } 
    }

    private Distance(decimal millimeters)
    {
        this.millimeters = millimeters;
    }

    public static Distance Yards(decimal yards)
    {
        return new Distance(yards * 914.4m);
    }
}

使用扩展方法,您和正确定义的运算符可以获得类似Ruby的语法:

var theWholeNineYards = 9.Yards() + 34.Inches();

答案 1 :(得分:2)

一般来说,我会选择 Anton 的解决方案。但是如果你的实现不能使用它,并且你需要使用与枚举类似的东西, 我认为这是使用单位的自然方式:

DistanceUnit.Metric.Millimeter  
DistanceUnit.Imperial.Inch  

为了像这样使用它,应该有:

public static class DistanceUnit  
{
  public static MetricDistanceUnit Metric;
  public static ImperialDistanceUnit Imperial;
}   

MetricDistanceUnit的位置:

public enum MetricDistanceUnit  
{
   Millimeter, Centimeter ...
}

ImperialDistanceUnit具有相同的结构..

答案 2 :(得分:1)

也许您只需要一个返回相应单位子集的函数

class UnitSystem
{
  public enum Type
  {
    Metric,
    Imperial
  }

  public static DistanceUnit[] GetUnits(Type type)
  {
    switch (type)
    {
      case Type.Metric:
        return new DistanceUnit[] {
          DistanceUnit.Millimeter,
          DistanceUnit.Centimeter,
          DistanceUnit.Meter,
          DistanceUnit.Kilometer
        }

      case Type.Imperial:
        return new DistanceUnit[] {
          DistanceUnit.Inch,
          DistanceUnit.Foot,
          DistanceUnit.Yard,
          DistanceUnit.Mile
        }
    }
  }

  public static Type GetType(DistanceUnit unit)
  {
    switch (unit)
    {
      case DistanceUnit.Millimeter:
      case DistanceUnit.Centimeter:
      case DistanceUnit.Meter:
      case DistanceUnit.Kilometer:
        return Type.Metric;

      case DistanceUnit.Inch:
      case DistanceUnit.Foot:
      case DistanceUnit.Yard:
      case DistanceUnit.Mile:
        return Type.Imperial;
    }
  }
}