前段时间和同事负责一个项目的两个业务模块,可能你们缺乏沟通,致使本该定义一个 Enum 的地方结果我俩各自定义了一个,致使后面这两个 Enum 进行对接就烦了,为了方便理解,也不想让你们看这崴脚的英文拼写,我就拿 银行 举例吧。git
public enum BankEnum { ICBC = 1, CMSB = 2, CMBC = 3 }
public enum ChinaBankEnum { 中国民生银行 = 1, 中国工商银行 = 2, 中国招商银行 = 3, }
这就很尬尴了,怎么将 ChinaBankEnum 转成 BankEnum 呢? 为了寻求多快好省,本篇就聊聊这个问题。程序员
本质上就是找两个 Enum 的 mapping 关系,人肉匹配那是最简单粗暴的,代码以下:github
static BankEnum ConvertToEnum(ChinaBankEnum chinaBank) { switch (chinaBank) { case ChinaBankEnum.中国工商银行: return BankEnum.ICBC; case ChinaBankEnum.中国民生银行: return BankEnum.CMSB; case ChinaBankEnum.中国招商银行: return BankEnum.CMBC; } return default(BankEnum); }
看的出来,这种写法缺乏灵活性,做为程序员确定不能知足于此,既然是找 mapping 关系,我相信不少朋友最先据说 mapping 一词是来源于 EntityFramework ,人家在处理 table 到 model 的 mapping 采用的是 Attribute,是否是这样,灵感就在于此,我是否是也可使用 Attribute 来标记两个 Enum 的对应关系呢???app
有了这个思路,就能够自定义一个 Attribute,固然比较懒的话,也能够用 Framework 自带的 DescriptionAttribute
,代码以下:测试
[AttributeUsage(AttributeTargets.All)] public class DescriptionAttribute : Attribute { public DescriptionAttribute(){} public DescriptionAttribute(string description){} }
接下来就能够把 Description 套在 BankEnum 上,以下代码所示:优化
public enum BankEnum { [Description(nameof(ChinaBankEnum.中国工商银行))] ICBC = 1, [Description(nameof(ChinaBankEnum.中国民生银行))] CMSB = 2, [Description(nameof(ChinaBankEnum.中国招商银行))] CMBC = 3 }
而后我能够经过反射拿到 Attribute 的值再去 ChinaBankEnum 中去找对应的 key 便可,对不对,为了方便理解,我封装一个 Enum 的扩展方法,经过反射实现 Enum 对 Enum 的转换,代码以下:this
/// <summary> /// 枚举的扩展方法 /// </summary> public static class EnumExtension { public static Target ConvertTo<Target>(this Enum enumValue) where Target : Enum { var key = Enum.GetName(enumValue.GetType(), enumValue); var fields = typeof(Target).GetFields(); foreach (var field in fields) { var attribute = field.GetCustomAttribute<DescriptionAttribute>(); if (attribute == null) continue; if (key == attribute.Description) { var obj = (Target)field.GetValue(typeof(Target)); return obj; } } return default(Target); } }
代码逻辑仍是比较简单的,接下来写两个例子测试下:spa
static void Main(string[] args) { ChinaBankEnum chinaBankEnum = ChinaBankEnum.中国工商银行; ChinaBankEnum chinaBankEnum2 = ChinaBankEnum.中国招商银行; var bankEnum = chinaBankEnum.ConvertTo<BankEnum>(); var bankEnum2 = chinaBankEnum2.ConvertTo<BankEnum>(); Console.WriteLine($"{chinaBankEnum} -> {bankEnum}\r\n{chinaBankEnum2} -> {bankEnum2}"); }
不知道你们在写代码的时候有没有发现将 string 或者 int 转成 Enum 的时候,写出来的代码是又臭又长,好比下面这样:code
var bankEnum = (ChinaBankEnum)Enum.Parse(typeof(ChinaBankEnum), "中国工商银行");
又是 typeof 又是类型强转换,并且强转不过来的话还会抛异常,基于各类缘由 framework 又新增了一个 TryParse,以下图所示:blog
看起来确实好多了,但仍是以为有点不爽,为了再顺眼一些,我决定在 EnumExtension 中再封装一个 TryParse 方法,以下代码所示:
public static class EnumExtension { public static T TryParse<T>(this string value) where T : struct { var isSucc = Enum.TryParse<T>(value, out var result); if (!isSucc) return default(T); return result; } }
调用的时候就能够这么来: var bankEnum = "中国工商银行".TryParse<ChinaBankEnum>();
,是否是就顺眼多了哈。
哈,本篇就来自于项目开发中遇到的一个坑,相信不少朋友都会遇到相似的状况,遗憾的是默认的 Enum 提供的功能太弱,你们能够根据本身的业务在 Enum 上扩充更多实用的方法,如获取全部的key,全部的value 等等,让本身的代码更加整洁,干净,强大!
更多高质量干货:参见个人 GitHub: dotnetfly