此为历史版本和 IPFS 入口查阅区,回到作品页
Leo
IPFS 指纹 这是什么

作品指纹

Visual Studio C# enum 用法:搭配 attribute 簡直逆天了!

Leo
·
·

Visual Studio C# enum 用法

如果你的同事都懂得善用 enum,請好好珍惜 …

  對於一個易讀易修改的 code,善用 enum 來取代單純數值的使用是一種較佳的做法!然而 enum 只能對應到數值的應用,若希望有更多的應用 e.g. string、struct、class,etc. 在一般情況下就只能兩手攤攤等死了。

  然而 Visual Studio 工程師果然不會讓人失望,能多便利就多便利,因此在使用 Visual Studio C# 時,可以透過為 enum 附加屬性 (Attribute) 並使用反射 (Reflection) 來取得更多的資訊,使 enum 不再只是對應到某個數值而已,更可以對應到更多的項目與資訊!偉哉 Dot Net Csharp 啊~

這是一般的 enum

public enum SampleEnum
{
    None = 0,
    MyEnum01,
    MyEnum02,
    MyEnum03,
};

這是加上了 attribute 後的 enum

public enum SampleEnum
{
    [System.ComponentModel.DescriptionAttribute("空的")]
    None,

    [System.ComponentModel.DescriptionAttribute("第一個")]
    MyEnum01,

    [System.ComponentModel.DescriptionAttribute("第二個")]
    MyEnum02,

    MyEnum03,
};

  在一般的 enum 中只能達到令 None = 0;MyEnum01 = 1;MyEnum02 = 2;MyEnum03 = 3,這樣的狀態而已,如果我希望 None;MyEnum01 … 可以代表一個對應的字串狀態,那就可以透過為 enum 加上 attribute 來表示。

  要為 enum 加上 attribute,只需要在要附加屬性的 enum 上方用中括號來表示要為某個 enum 添加一個屬性,並且在中括號內輸入一個 attribute 的 class,如上述的 code 就是用了一個 system 的 description attribute。因此現在 None、MyEnum01、MyEnum02 都被附加上屬性了,而 MyEnum03 則是沒有被附加上屬性。

若 system 的 description attribute 無法滿足你的需求時,也可以繼承 attribute abstract class 來創造自己的 attribute!

加上自己創造的 attribute 後的 enum 簡直美的我都睜不開眼了

public class SampleEnumAttribute : Attribute
{
    private string _text = string.Empty;

    public SampleEnumAttribute(string text)
    {
        _text = text;
    }

    public string Text => _text;
}

/* 就可以將上面的 "System.ComponentModel.DescriptionAttribute" 取代成 "SampleEnumAttribute" */
public enum SampleEnum
{
    [SampleEnumAttribute("空的")]
    None,

    [SampleEnumAttribute("第一個")]
    MyEnum01,

    [SampleEnumAttribute("第二個")]
    MyEnum02,

    MyEnum03,
};

接著就可以透過 Reflection 來獲得 Attribute 中的資訊:

※ 以下為自定義擴充方法的寫法,若尚不清楚此種用法可以參考:Visual Studio C# 擴充方法讓程式碼更好看,人生更完整了

public static class SampleEnumExtension
{
    public static string GetSampleEnumText(this SampleEnum sample)
    {
        System.Reflection.FieldInfo fi = sample.GetType().GetField(sample.ToString());
        if (fi.GetCustomAttribute(typeof(SampleEnumAttribute), false) is SampleEnumAttribute attribute)
        {
            return attribute.Text;
        }
        else
            return null;
    }
}

將上述提到的附加屬性 (Attribute) 的方法搭配反射 (Reflection) 結合起來使用,就可以得到如下的結果:

private static void Main(string[] args)
{
    var text = string.Empty;
    Console.WriteLine("/// <output>");
    text = SampleEnum.None.GetSampleEnumText();
    Console.WriteLine($"/// {nameof(SampleEnum.None)} 的 Attribute 訊息: {text}, {nameof(string.IsNullOrEmpty)}: {string.IsNullOrEmpty(text)}");
    text = SampleEnum.MyEnum01.GetSampleEnumText();
    Console.WriteLine($"/// {nameof(SampleEnum.MyEnum01)} 的 Attribute 訊息: {text}, {nameof(string.IsNullOrEmpty)}: {string.IsNullOrEmpty(text)}");
    text = SampleEnum.MyEnum02.GetSampleEnumText();
    Console.WriteLine($"/// {nameof(SampleEnum.MyEnum02)} 的 Attribute 訊息: {text}, {nameof(string.IsNullOrEmpty)}: {string.IsNullOrEmpty(text)}");
    text = SampleEnum.MyEnum03.GetSampleEnumText();
    Console.WriteLine($"/// {nameof(SampleEnum.MyEnum03)} 的 Attribute 訊息: {text}, {nameof(string.IsNullOrEmpty)}: {string.IsNullOrEmpty(text)}");
    Console.WriteLine("/// </output>");
    Console.ReadLine();
}

/// <output>
/// None 的 Attribute 訊息: 空的, IsNullOrEmpty: False
/// MyEnum01 的 Attribute 訊息: 第一個, IsNullOrEmpty: False
/// MyEnum02 的 Attribute 訊息: 第二個, IsNullOrEmpty: False
/// MyEnum03 的 Attribute 訊息: , IsNullOrEmpty: True
/// </output>

可以得到 None、MyEnum01、MyEnum02 的字串訊息、並且 MyEnum03 因為沒有附加 Attribute 所以返回的 string 為 null。

原文連結Leo Studio

CC BY-NC-ND 2.0 授权