簡體   English   中英

java enums vs C#enums - 缺少功能

[英]java enums vs C# enums - missing features

在java中,我可以輕松地描述帶有aditional數據的枚舉。
我可以形容這樣的事情

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#,我的選擇是什么?
我想要保存帶有屬性的枚舉,將其加載到地圖中,並在需要時按鍵進行檢索。 我有什么需要幫助的嗎(比如每個枚舉的單音 - 這不是一個好主意)。
謝謝。

我只想創建一個類,每個類型的public static readonly實例和ditch枚舉。 您可以將它們用作字典鍵或做任何您喜歡的事情。 如果您仍打算將它們映射到基礎數據類型( 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轉換。

最方便的解決方法可能是為枚舉類型創建擴展方法,並返回關聯的符號。

像這樣的東西:

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

當然你可以編寫一個更復雜的擴展方法,帶有返回值等,這只是一個如何做的例子。

C#實際上沒有相同的功能。 然而,有幾種可能性非常接近(也可能更靈活)。

堅持常規枚舉,您可以使用屬性來豐富額外信息。 當然,這需要反思才能實現

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

有幾種模式可以解決這個問題,例如http://www.codeproject.com/Articles/28087/DisplayNameAttribute-for-Enumerations,google了解更多。

另一種方法是使用常規類來增強枚舉類型:

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#中使用類似枚舉類型的一些其他方法

您可以創建一個屬性:

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)。 如果要按鍵查找,只需創建其他使用字符串值作為鍵的擴展方法。

如果您確實需要C#中Java風格枚舉的功能,我會看到三種合理的方法來實現它:

  1. 使用C#枚舉和靜態類輔助方法。 你失去了類型安全性,但這是一個非常可行的解決方案。

  2. 使用C#枚舉和一組擴展方法。 可能是最慣用的C#解決方案,但您仍然必須處理類型安全性的損失(您的擴展方法應該能夠處理超出范圍的值,即使只是拋出異常)。

  3. 在Java 5中獲得enum關鍵字的語言之前,使用Java中常見的類型安全枚舉模式 。如果每個枚舉值都有非平凡的邏輯,那么這將是我的偏好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM