- A+
今天和大家享一些关于枚举操作相关的常用扩展方法。
我们平时用的比较多的是正常枚举,同时还有加[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