10

在 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 并允许通过其属性之一作为键从映射中检索完整枚举数据。

简而言之,枚举是java中一个非常发达的类型。

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

4

5 回答 5

9

我只会创建一个包含public static readonly每种类型实例的类,然后完全放弃枚举。您可以将它们用作字典键或做任何您喜欢的事情。如果您仍打算将它们映射到基础数据类型 ( 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转换。

于 2012-11-18T22:33:45.560 回答
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
    }
}

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

于 2012-11-18T22:33:38.193 回答
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;
   }
}

本文介绍了在 C# 中使用类枚举类型的其他一些方法

于 2012-11-18T22:32:53.430 回答
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

请注意空引用异常(因为如果找不到属性,它将返回空)。如果您想按键查找,您可以简单地创建使用字符串值作为键的其他扩展方法。

于 2012-11-18T22:59:49.447 回答
0

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

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

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

  3. 在 Java 5中获得关键字之前,使用 Java 中常见的类型安全枚举模式enum。如果您对每个枚举值都有非平凡的逻辑,这将是我的首选。

于 2012-11-18T22:32:43.280 回答