【问题标题】:Associating Additional Information with .NET Enum将附加信息与 .NET 枚举关联
【发布时间】:2009-03-25 06:58:33
【问题描述】:

我的问题最好用一个例子来说明。

假设我有枚举:

public enum ArrowDirection
{
    North,
    South,
    East,
    West
}

我想将每个方向对应的单位向量与那个方向相关联。例如,我想要返回 (0, 1) 代表 North,返回 (-1, 0) 代表 West 等的东西。我知道在 Java 中您可以在枚举中声明一个可以提供该功能的方法。

我当前的解决方案是有一个静态方法——在定义枚举的类中——返回一个与传入的 ArrowDirection 相对应的向量(该方法使用 HashTable 来完成查找,但这并不重要)。这似乎……不干净。

问题:
在 .NET 中存储与枚举对应的附加信息是否有最佳实践解决方案?

【问题讨论】:

  • 也可以使用旧的工厂方法..

标签: c# .net enums


【解决方案1】:

在 C# 3.0 中有一种非常棒的新方法可以做到这一点。关键是这个美丽的事实:枚举可以有扩展方法!所以,你可以这样做:

public enum ArrowDirection
{
    North,
    South,
    East,
    West
}

public static class ArrowDirectionExtensions
{
     public static UnitVector UnitVector(this ArrowDirection self)
     {
         // Replace this with a dictionary or whatever you want ... you get the idea
         switch(self)
         {
             case ArrowDirection.North:
                 return new UnitVector(0, 1);
             case ArrowDirection.South:
                 return new UnitVector(0, -1);
             case ArrowDirection.East:
                 return new UnitVector(1, 0);
             case ArrowDirection.West:
                 return new UnitVector(-1, 0);
             default:
                 return null;
         }
     }
}

现在,你可以这样做了:

var unitVector = ArrowDirection.North.UnitVector();

甜!大约一个月前我才发现这一点,但这是 C# 3.0 新特性带来的一个非常好的结果。

Here's another example on my blog.

【讨论】:

  • 这很酷。虽然我知道扩展,但我从未想过将它们用于枚举扩展
  • 是的,我也是。一个朋友告诉我这件事。这是很不错的。我也很惊讶地得知(最近,在 SO 上)您可以在空值上调用扩展方法。它仍然有效,因为它是一种静态方法。像往常一样,C# 团队在考虑这些特性方面做得很好。
  • 你会得到公认的答案。我试过了,效果很好。唯一的事情是。我应该在哪里声明枚举?如果我把它留在课堂上,它会说它不太容易访问。我必须创建一个“ClassName_Enums”类才能使其工作......
  • 事实证明在命名空间级别定义枚举是有意义的。接受。
  • 是的,我同意在大多数情况下我会使用命名空间级别。
【解决方案2】:

我已经在博客here

Attributes试试这样的东西。

  public enum Status {

    [Status(Description = "Not Available")]      

    Not_Available = 1,      

    [Status(Description = "Available For Game")] 

    Available_For_Game = 2,      

    [Status(Description = "Available For Discussion")] 

    Available_For_Discussion = 3,

  }

  public class StatusEnumInfo {

    private static StatusAttribute[] edesc; 

    public static String GetDescription(object e)

    {

      System.Reflection.FieldInfo f = e.GetType().GetField(e.ToString()); 

      StatusEnumInfo.edesc = f.GetCustomAttributes(typeof(StatusAttribute), false) as StatusAttribute[]; 

      if (StatusEnumInfo.edesc != null && StatusEnumInfo.edesc.Length == 1)         

        return StatusEnumInfo.edesc[0].Description; 

      else         

        return String.Empty;

    } 

    public static object GetEnumFromDesc(Type t, string desc)

    {

      Array x = Enum.GetValues(t); 

      foreach (object o in x) {

        if (GetDescription(o).Equals(desc)) {

          return o;

        }

      } return String.Empty;

    }

  }

  public class StatusAttribute : Attribute {

    public String Description { get; set; }

  }



  public class Implemenation {

    public void Run()

    {

      Status statusEnum = (Status)StatusEnumInfo.GetEnumFromDesc(typeof(Status), "Not Available"); 

      String statusString = StatusEnumInfo.GetDescription(Status.Available_For_Discussion);

    }

  }

使用您的自定义属性代替描述

【讨论】:

    【解决方案3】:
    using System.ComponentModel;
    using System.Reflection;
    
    
    public enum ArrowDirection
    {
    
    [Description("Northwards")]
    North,
    
    [Description("Southwards")]
    South,
    
    [Description("Eastwards")]
    East,
    
    [Description("Westwards")]
    West
    }
    

    ...

    创建一个扩展方法来获取描述列表:

    public static class Enum<T> where T : struct
    {
    
        /// <summary>
        /// Gets a collection of the enum value descriptions.
        /// </summary>
        /// <returns></returns>
        public static IList<string> GetDescriptions()
        {
            List<string> descriptions = new List<string>();
            foreach (object enumValue in Enum<T>.GetValues())
            {
                descriptions.Add(((Enum)enumValue).ToDescription());
            }
            return descriptions;
    
        }
    }
    

    【讨论】:

    • 这看起来不像是扩展方法。 this 参数在哪里?另外,ToDescription 来自哪里?那应该是扩展方法吗?
    【解决方案4】:

    您可以查看的一件事是“类型安全枚举”模式。这允许您创建一个实际上是一个成熟的静态对象的枚举,它可以具有方法/属性/等。

    http://www.javacamp.org/designPattern/enum.html

    Joshua Bloch 在他的“Effective Java”一书中谈到了这种模式。我在很多不同的情况下都使用过它,实际上我更喜欢它而不是普通的枚举。 (它与语言无关 - 它适用于 Java、C# 或几乎任何 OO 语言)。

    【讨论】:

    • 我也用过,很喜欢。但直到最近我才发现我更喜欢的东西。您可以将扩展方法放在枚举上!有趣的是,这给我带来了多少乐趣……但真的很好。
    【解决方案5】:

    您的静态方法方法对我来说似乎很干净。您将枚举和静态方法封装在同一个类中。对枚举的更改集中在该单个类中。

    向枚举添加一个方法(根据 Java)似乎增加了一些非常简单的概念的复杂性。

    基于属性的方法很有趣,但与静态方法相比,这似乎又过于复杂了。

    【讨论】:

      猜你喜欢
      • 2016-04-24
      • 1970-01-01
      • 2016-06-09
      • 1970-01-01
      • 1970-01-01
      • 2016-07-15
      • 2012-06-18
      • 2017-03-17
      • 1970-01-01
      相关资源
      最近更新 更多