今天和大家享一些關於列舉操作相關的常用擴充套件方法。
我們平時用的比較多的是正常列舉,同時還有加[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