java enums vs C#enums - 缺少功能

时间:2012-11-18 22:15:40

标签: c# java enums

在java中我可以很容易地描述一个带有附加数据的枚举 我可以形容这样的事情

public enum OperatorType
{
    GreaterOrEqual  (">=", "GreaterOrEqual"),
    Greater         (">" ,"Greater"),
    Less            ("<", "Less"),
    LessOrEqual     ("<=", "LessOrEqual"),
    Equal           ("==", "Equal"),
    Between         ("Between", "Between"),
    Around          ("Around","Around");

    private final String symbol;
    private final String name;

    private OperatorType(final String symbol, final String name) {
        this.symbol = symbol;
        this.name = name;
    }
}

然后添加一个迭代values()的静态方法,将所有数据添加到hashmap中,并允许通过其中一个属性作为键从地图中检索完整枚举数据。

简而言之,enum是java中非常发达的类型。

现在,
转到c#,我的选择是什么? 我想要保存带有属性的枚举,将其加载到地图中,并在需要时按键进行检索。我有什么可以帮助的吗(比如,每个枚举的单音 - 这不是一个好主意) 感谢。

5 个答案:

答案 0 :(得分:8)

我只想创建一个类,每个类型的public static readonly个实例和ditch enums。您可以将它们用作字典键或做任何您喜欢的事情。如果您仍打算将它们映射到基础数据类型(int),那么您也可以为此创建隐式运算符。

public class OperatorType
{
    private static readonly Dictionary<int, OperatorType> OperatorMapping = new Dictionary<int, OperatorType>();

    public static readonly OperatorType GreaterOrEqual  = new OperatorType(0, ">=", "GreaterOrEqual");
    public static readonly OperatorType Greater         = new OperatorType(1, ">", "Greater");



    public readonly String symbol;
    public readonly String name;
    private readonly int underlyingValue;

    private OperatorType(int underlyingValue, string symbol, string name) {
        this.underlyingValue = underlyingValue;
        OperatorMapping[underlyingValue] = this;

        this.symbol = symbol;
        this.name = name;
    }

    public static implicit operator int(OperatorType operatorType)
    {
        return operatorType.underlyingValue;
    }

    public static implicit operator OperatorType(int value)
    {
        return OperatorMapping[value];
    }
}

样本用法:

Dictionary<OperatorType, string> operators = new Dictionary<OperatorType, string>();

operators.Add(OperatorType.GreaterOrEqual, "Greater or equal");

Console.WriteLine(operators[OperatorType.GreaterOrEqual]); //"Greater or equal"

OperatorType operatorType = 1;

Console.WriteLine(operatorType.name); //"Greater"

如果您不关心基础价值,请不要包含它。还要考虑Dictionary映射是否应该是您使用的线程安全。如果需要,还可以公开静态IEnumerable<OperatorType>(或其他集合)以定义所有运算符。

编辑:第二个想法,explicit运算符可能更可取代implicit,以符合典型的.NET最佳做法,并更好地匹配典型的enum转换。

答案 1 :(得分:4)

最方便的解决方法可能是为枚举类型创建一个扩展方法,并返回相关的符号。

这样的事情:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            tester t = tester.x;
            t.testenums();
            Console.ReadKey();
        }


    }

    public static class ext
    {
        public static void testenums(this tester x)
        {
            Console.WriteLine(x.ToString());
        }
    }

    public enum tester
    {
        x,
        y
    }
}

当然你可以编写一个更复杂的扩展方法,带有返回值等,这只是一个如何做的例子。

答案 2 :(得分:2)

C#实际上没有相同的功能。然而,有几种可能性非常接近(也可能更灵活)。

坚持常规枚举,您可以使用属性来丰富额外信息。当然,这需要反思才能与

一起使用
public enum OperatorType
{
    [DisplayName(">=")]
    GreaterOrEqual,
    // ...
}

有几种模式适用于此,例如http://www.codeproject.com/Articles/28087/DisplayNameAttribute-for-Enumerations,谷歌了解更多。

另一种方法是使用常规类来增强枚举类型:

public class OperatorType
{
   public static OperatorType GreaterOrEqual = new OperatorType(">=", "GreaterOrEqual");
   // ...

   string symbol;
   string name;
   private OperatorType(string symbol, string name)
   {
       this.symbol = symbol;
       this.name = name;
   }
}

This article描述了在C#

中使用类似枚举类型的其他一些方法

答案 3 :(得分:2)

您可以创建一个属性:

public class EnumKeyAttribute : Attribute
{
    public string Key { get; set; }

    public string Description { get; set; }

    public EnumKeyAttribute(string key, string description)
    {
        this.Key = key;
        this.Description = description;
    }
}

然后将其应用于您的枚举

public enum OperatorType
{
    [EnumKey(">=", "GreaterOrEqual")]
    GreaterOrEqual,

    [EnumKey(">", "Greater")]
    Greater,

    [EnumKey("<", "Less")]
    Less,

    [EnumKey("<=", "LessOrEqual")]
    LessOrEqual,

    [EnumKey("==", "Equal")]
    Equal,

    [EnumKey("Between", "Between")]
    Between,

    [EnumKey("Around", "Around")]
    Around
}

要获取属性数据,您可以使用反射。以下是获取“Less”

属性的示例
        MemberInfo memberInfo = typeof(OperatorType).GetMember(OperatorType.Less.ToString()).FirstOrDefault();

        if(memberInfo != null)
        {
            EnumKeyAttribute attribute = (EnumKeyAttribute)memberInfo.GetCustomAttributes(typeof(EnumKeyAttribute), false).FirstOrDefault();

            Console.WriteLine(attribute.Key);
            Console.WriteLine(attribute.Description);
        }

但是因为这些枚举不是在运行时创建的,所以可以通过创建一个在字典中查找值的静态方法来提高效率。这是一种易于使用的扩展方法

public static class KeyFinder
{
    private static Dictionary<OperatorType, EnumKeyAttribute> lookupTable =
        new Dictionary<OperatorType, EnumKeyAttribute>();

    public static EnumKeyAttribute GetKey(this OperatorType type)
    {

        if (lookupTable.ContainsKey(type))
        {
            return lookupTable[type];
        }

        MemberInfo memberInfo = typeof(OperatorType).GetMember(type.ToString()).FirstOrDefault();

        if (memberInfo != null)
        {
            EnumKeyAttribute attribute = (EnumKeyAttribute)memberInfo.GetCustomAttributes(typeof(EnumKeyAttribute), false).FirstOrDefault();

            if (attribute != null)
            {
                lookupTable.Add(type, attribute);
                return attribute;
            }
        }

        // add a null value so next time it doesn't use reflection only to find nothing
        lookupTable.Add(type, null);

        return null;
    }
}

现在要获取值,您只需执行以下操作:

OperatorType.Less.GetKey().Key
OperatorType.Less.GetKey().Description

请注意空引用异常(因为如果找不到属性,它将返回null)。如果要按键查找,只需创建其他使用字符串值作为键的扩展方法。

答案 4 :(得分:0)

如果你真的需要C#中Java风格枚举的功能,我会看到三种合理的方法来实现它:

  1. 使用C#枚举和静态类辅助方法。你失去了类型安全性,但这是一个非常可行的解决方案。

  2. 使用C#枚举和一组扩展方法。可能是最惯用的C#解决方案,但您仍然需要处理类型安全性的损失(您的扩展方法应该能够处理超出范围的值,即使只是抛出异常)。

    < / LI>
  3. 在Java 5中获得enum关键字的语言之前,使用Java中常见的type-safe enum pattern。如果每个枚举值都有非平凡的逻辑,那么这将是我的偏好