開源 - Ideal庫 - 常用列舉擴充套件方法(一)

IT规划师發表於2024-11-13

今天和大家享一些關於列舉操作相關的常用擴充套件方法。

我們平時用的比較多的是正常列舉,同時還有加[Flags]特性的位標誌列舉,因此以下所有擴充套件方法同時適用正常列舉以及位標誌列舉。

我們首先定義兩種列舉用於下面擴充套件方法測試適用,程式碼如下:

//正常列舉
internal enum StatusEnum
{
    [Description("正常")]
    Normal = 0,
    [Description("待機")]
    Standby = 1,
    [Description("離線")]
    Offline = 2,
    Online = 3,
}
//位標誌列舉
[Flags]
internal enum TypeFlagsEnum
{
    [Description("Http協議")]
    Http = 1,
    [Description("Udp協議")]
    Udp = 2,
    [Description("Http協議,Udp協議")]
    HttpAndUdp = 3,
    [Description("Tcp協議")]
    Tcp = 4,
}

01、根據列舉名稱轉換成列舉

該方法接收列舉名稱字串,並轉為對應列舉,轉換失敗則返回空。

首先會校驗字串是否為整數值型別字串,如果是則直接返回空,因為列舉名稱不可能是整數型別字串。

然後呼叫TryParse方法進行轉換,具體程式碼如下:

//根據列舉名稱轉換成列舉,轉換失敗則返回空
public static T? ToEnumByName<T>(this string name) where T : struct, Enum
{
    //如果為整數型別字串,則直接返回空
    if (int.TryParse(name, out _))
    {
        return default;
    }
    //轉換成功則返回結果,否則返回空
    if (Enum.TryParse<T>(name, out var result))
    {
        return result;
    }
    return default;
}

下面我們對其進行詳細的單元測試,分別針對正常列舉和位標誌列舉兩種情況測試,具體用例如下:

(1) 正常列舉名稱字串,成功轉換成列舉;

(2) 不存在的列舉名稱字串,返回空;

(3) 整數型別的字串,返回空;

(4) 正常位標誌列舉名稱字串,成功轉換成列舉;

(5) 不存在的位標誌列舉名稱字串,返回空;

(6) 正常的位標誌列舉名稱組合字串,成功轉換成列舉;

(7) 不存在的位標誌列舉名稱組合字串,返回空;

位標誌列舉名稱組合字串是指兩個列舉項組合的情況,這也是位標誌列舉特色,不瞭解位標誌列舉的可以自行先補充一下相關知識點。

具體程式碼如下:

[Fact]
public void ToEnumByName()
{
    //正常列舉名稱字串,成功轉換成列舉
    var status = "Standby".ToEnumByName<StatusEnum>();
    Assert.Equal(StatusEnum.Standby, status);
    //不存在的列舉名稱字串,返回空
    var isStatusNull = "StandbyNull".ToEnumByName<StatusEnum>();
    Assert.Null(isStatusNull);
    //整數型別的字串,返回空
    var isStatusNullInt = "3".ToEnumByName<StatusEnum>();
    Assert.Null(isStatusNullInt);
    //正常位標誌列舉名稱字串,成功轉換成列舉
    var flags = "HttpAndUdp".ToEnumByName<TypeFlagsEnum>();
    Assert.Equal(TypeFlagsEnum.HttpAndUdp, flags);
    //不存在的位標誌列舉名稱字串,返回空
    var isFlagsNull = "HttpAndUdpNull".ToEnumByName<TypeFlagsEnum>();
    Assert.Null(isFlagsNull);
    //正常的位標誌列舉名稱組合字串,成功轉換成列舉
    var flagsGroup = "Http,Tcp".ToEnumByName<TypeFlagsEnum>();
    Assert.Equal(TypeFlagsEnum.Http | TypeFlagsEnum.Tcp, flagsGroup);
    //不存在的位標誌列舉名稱組合字串,返回空
    var isFlagsGroupNull = "Http,Tcp,Null".ToEnumByName<TypeFlagsEnum>();
    Assert.Null(isFlagsGroupNull);
}

02、根據列舉名稱轉換成列舉或預設值

該方法是對上一個方法的補充,用於處理轉換不成功時,則返回一個指定預設列舉值,具體程式碼如下:

//根據列舉名稱轉換成列舉,轉換失敗則返回預設列舉
public static T ToEnumOrDefaultByName<T>(this string name, T defaultValue) where T : struct, Enum
{
    //呼叫根據列舉名稱轉換成列舉方法
    var result = name.ToEnumByName<T>();
    if (result.HasValue)
    {
        return result.Value;
    }
    //轉換失敗則返回預設值
    return defaultValue;
}

因為該方法呼叫了上一個方法,因此我們就簡單測試一下,轉換成功返回正確的值,轉換失敗則返回預設值,具體程式碼如下:

[Fact]
public void ToEnumOrDefaultByName()
{
    //正常列舉名稱字串,成功轉換成列舉
    var status = "Standby".ToEnumOrDefaultByName(StatusEnum.Normal);
    Assert.Equal(StatusEnum.Standby, status);
    //不存在的列舉名稱字串,返回指定預設值
    var statusDefault = "StandbyNull".ToEnumOrDefaultByName(StatusEnum.Standby);
    Assert.Equal(StatusEnum.Standby, statusDefault);
}

03、根據列舉描述轉換成列舉

該方法接收列舉描述字串,並轉為對應列舉,轉換失敗則返回空,其中如果列舉項沒有描述則以列舉名稱代替,具體程式碼如下:

//根據列舉描述轉換成列舉,轉換失敗返回空
public static T? ToEnumByDesc<T>(this string description) where T : struct, Enum
{
    //首先獲取列舉所有項
    foreach (Enum value in Enum.GetValues(typeof(T)))
    {
        //取列舉項描述與目標描述相比較,相同則返回該列舉項
        if (value.ToEnumDesc() == description)
        {
            return (T)value;
        }
    }
    //未查到匹配描述則返回預設值
    return default;
}

其中ToEnumDesc方法下文會詳細講解。

我們針對該方法進行以下五種情況進行單元測試:

(1) 正常列舉描述字串,成功轉換成列舉;

(2) 如果列舉項沒有列舉描述,則列舉名稱字串,成功轉換成列舉;

(3) 不存在的列舉描述字串,返回空;

(4) 正常位標誌列舉描述字串,成功轉換成列舉;

(5) 不存在的位標誌列舉描述字串轉換,返回空;

具體程式碼如下:

[Fact]
public void ToEnumByDescription()
{
    //正常列舉描述字串,成功轉換成列舉
    var status = "待機".ToEnumByDesc<StatusEnum>();
    Assert.Equal(StatusEnum.Standby, status);
    //如果列舉項沒有列舉描述,則列舉名稱字串,成功轉換成列舉
    var statusNotDesc = "Online".ToEnumByDesc<StatusEnum>();
    Assert.Equal(StatusEnum.Online, statusNotDesc);
    //不存在的列舉描述字串,返回空
    var isStatusNull = "待機無".ToEnumByDesc<StatusEnum>();
    Assert.Null(isStatusNull);
    //正常位標誌列舉描述字串,成功轉換成列舉
    var flags = "Http協議,Udp協議".ToEnumByDesc<TypeFlagsEnum>();
    Assert.Equal(TypeFlagsEnum.HttpAndUdp, flags);
    //不存在的位標誌列舉描述字串轉換,返回空
    var isFlagsNull = "Http協議Udp協議".ToEnumByDesc<TypeFlagsEnum>();
    Assert.Null(isFlagsNull);
}

04、根據列舉描述轉換成列舉或預設值

該方法是對上一個方法的補充,用於處理轉換不成功時,則返回一個指定預設列舉值,其中如果列舉項沒有描述則以列舉名稱代替,具體程式碼如下:

//根據列舉描述轉換成列舉,轉換失敗返回預設列舉
public static T? ToEnumOrDefaultByDesc<T>(this string description, T defaultValue) where T : struct, Enum
{
    //呼叫根據列舉描述轉換成列舉方法
    var result = description.ToEnumByDesc<T>();
    if (result.HasValue)
    {
        return result.Value;
    }
    //未查到匹配描述則返回預設值
    return defaultValue;
}

同樣的我們進行簡單的單元測試:

[Fact]
public void ToEnumOrDefaultByDesc()
{
    //正常列舉描述字串,成功轉換成列舉
    var status = "待機".ToEnumOrDefaultByDesc(StatusEnum.Offline);
    Assert.Equal(StatusEnum.Standby, status);
    //不存在的列舉描述字串,返回指定預設值
    var statusDefault = "待機無".ToEnumOrDefaultByDesc(StatusEnum.Offline);
    Assert.Equal(StatusEnum.Offline, statusDefault);
}

05、根據列舉名稱轉換成列舉值

該方法接收列舉名字字串,並轉為對應列舉值,轉換失敗則返回空,具體程式碼如下:

//根據列舉名稱轉換成列舉值,轉換失敗則返回空
public static int? ToEnumValueByName<T>(this string name) where T : struct, Enum
{
    //呼叫根據列舉名稱轉換成列舉方法
    var result = name.ToEnumByName<T>();
    if (result.HasValue)
    {
        return Convert.ToInt32(result.Value);
    }
    //轉換失敗則返回空
    return default;
}

我們對其進行以下五種情況做詳細的單元測試:

(1) 正常列舉名稱字串,成功轉換成列舉值;

(2) 不存在的列舉名稱字串,返回空;

(3) 正常位標誌列舉名稱字串,成功轉換成列舉值;

(4) 正常的位標誌列舉名稱組合字串,成功轉換成列舉值;

(5) 不存在的位標誌列舉Int值轉換則返回空;

具體程式碼如下:

[Fact]
public void ToEnumValueByName()
{
    //正常列舉名稱字串,成功轉換成列舉值
    var status = "Standby".ToEnumValueByName<StatusEnum>();
    Assert.Equal(1, status);
    //不存在的列舉名稱字串,返回空
    var isStatusNull = "StandbyNull".ToEnumValueByName<StatusEnum>();
    Assert.Null(isStatusNull);
    //正常位標誌列舉名稱字串,成功轉換成列舉值
    var flags = "HttpAndUdp".ToEnumValueByName<TypeFlagsEnum>();
    Assert.Equal(3, flags);
    //正常的位標誌列舉名稱組合字串,成功轉換成列舉值
    var flagsGroup = "Http,Udp".ToEnumValueByName<TypeFlagsEnum>();
    Assert.Equal(3, flagsGroup);
    //不存在的位標誌列舉名稱字串,返回空
    var isFlagsNull = "HttpUdp".ToEnumValueByName<TypeFlagsEnum>();
    Assert.Null(isFlagsNull);
}

06、根據列舉名稱轉換成列舉值或預設值

該方法是對上一個方法的補充,用於處理轉換不成功時,則返回一個指定預設列舉值,具體程式碼如下:

//根據列舉名稱轉換成列舉值,轉換失敗則返回預設列舉值
public static int ToEnumValueOrDefaultByName<T>(this string name, int defaultValue) where T : struct, Enum
{
    //根據列舉名稱轉換成列舉值
    var result = name.ToEnumValueByName<T>();
    if (result.HasValue)
    {
        return result.Value;
    }
    //轉換失敗則返回預設值
    return defaultValue;
}

我們進行簡單的單元測試,具體程式碼如下:

[Fact]
public void ToEnumValueOrDefaultByName()
{
    //正常列舉名稱字串,成功轉換成列舉值
    var status = "Standby".ToEnumValueOrDefaultByName<StatusEnum>(2);
    Assert.Equal(1, status);
    //不存在的列舉名稱字串,返回指定預設值
    var statusDefault = "StandbyNull".ToEnumValueOrDefaultByName<StatusEnum>(2);
    Assert.Equal(2, statusDefault);
}

07、根據列舉名稱轉換成列舉描述

該方法接收列舉名字字串,並轉為對應列舉描述,轉換失敗則返回空,其中如果列舉項沒有描述則以列舉名稱代替,具體程式碼如下:

//根據列舉名稱轉換成列舉描述,轉換失敗則返回空
public static string? ToEnumDescByName<T>(this string name) where T : struct, Enum
{
    //呼叫根據列舉名稱轉換成列舉方法
    var result = name.ToEnumByName<T>();
    if (result.HasValue)
    {
        //轉為列舉描述
        return result.Value.ToEnumDesc();
    }
    //轉換失敗則返回空
    return default;
}

因為該方法內部都是呼叫現有方法,因此做個簡單單元測試,具體程式碼如下:

[Fact]
public void ToEnumDescByName()
{
    //正常位標誌列舉名稱字串,成功轉換成列舉描述
    var flags = "HttpAndUdp".ToEnumDescByName<TypeFlagsEnum>();
    Assert.Equal("Http協議,Udp協議", flags);
    //正常的位標誌列舉名稱組合字串,組合項存在,成功轉換成列舉描述
    var flagsGroup = "Http,Udp".ToEnumDescByName<TypeFlagsEnum>();
    Assert.Equal("Http協議,Udp協議", flagsGroup);
    //正常的位標誌列舉名稱組合字串,組合項不存在,成功轉換成列舉描述
    var flagsGroup1 = "Http,Tcp".ToEnumDescByName<TypeFlagsEnum>();
    Assert.Equal("Http協議,Tcp協議", flagsGroup1);
}

08、根據列舉名稱轉換成列舉描述或預設值

該方法是對上一個方法的補充,用於處理轉換不成功時,則返回一個指定預設列舉描述,具體程式碼如下:

//根據列舉名稱轉換成列舉描述,轉換失敗則返回預設列舉描述
public static string ToEnumDescOrDefaultByName<T>(this string name, string defaultValue) where T : struct, Enum
{
    //呼叫根據列舉名稱轉換成列舉描述方法
    var result = name.ToEnumDescByName<T>();
    if (!string.IsNullOrWhiteSpace(result))
    {
        return result;
    }
    //轉換失敗則返回預設列舉描述
    return defaultValue;
}

做個簡單單元測試,具體程式碼如下:

[Fact]
public void ToEnumDescOrDefaultByName()
{
    //正常列舉名稱字串,成功轉換成列舉描述
    var status = "Standby".ToEnumDescOrDefaultByName<StatusEnum>("測試");
    Assert.Equal("待機", status);
    //不存在的列舉名稱字串,返回指定預設列舉描述
    var statusDefault = "StandbyNull".ToEnumDescOrDefaultByName<StatusEnum>("測試");
    Assert.Equal("測試", statusDefault);
}

稍晚些時候我會把庫上傳至Nuget,大家可以直接使用Ideal.Core.Common。

:測試方法程式碼以及示例原始碼都已經上傳至程式碼庫,有興趣的可以看看。https://gitee.com/hugogoos/Ideal

相關文章