C# 通过枚举类型字符串,反射到枚举上
- 通过类型字符串,反射出任意类型
- 枚举类型
- 通过反射调用枚举
- GetTypeByName(EnumName) 为空?
- 小结
通过类型字符串,反射出任意类型
之前老顾写过一篇博客,通过反射,使用字符串,可以反射出当前项目中所有可用的类型,包括泛型类型。需要补课的小伙伴可以围观下老顾之前的文章《C# 根据typename字符串,创建任意类型的对象(含泛型)》。
虽然老顾自己也说了,使用这个方法,一般都是自己掉坑里的选择,不过确实有时候也会用到。
枚举类型
一般在自己开发的程序中,针对于特定的有限数据,我们一般会做出一个枚举类型,来规范所有参与项目的小伙伴,避免出现歧义或不规范内容。
比如,一个订单状态,根据业务流程,我们可以分成几个阶段:
提交未处理
已接收订单
待付款
已付款
待发货
正在配送
已配送完成
订单完成
等等这样的有限状态集合。
也比如说,访问网络资源,会返回一些状态码,比如 200、404、401、500 之类的,这些都是有限状态,所以通常我们都可以用 Enum 来定义一个枚举集合,规范一下数据。
这样的操作,主要是为了避免有的小伙伴写做待付款,有的小伙伴写做未付款,还有的写作待支付。。。总之,不用枚举规范的话,天知道会出现多少相同意义的数据。
CSDN 文盲老顾的博客,https://blog.csdn.net/superwfei
老顾的个人社区,https://bbs.csdn.net/forums/bfba6c5031e64c13aa7c60eebe858a5f?category=10003&typeId=3364713
通过反射调用枚举
大多数时候,我们在使用枚举的时候,都是明确知道其类型的,所以,我们通常是直接用 Enum.GetName(枚举类型,值) 的方式来获取对应的文本描述。
但是,偶尔,我们需要调用枚举的位置,并不是我们手写的代码,而是类似模版定义这样的内容,比如,现在老顾就有这么一个模板定义:
404.enum.httpstate
404 是值,enum 是调用枚举,httpstate 是枚举类型
正常在程序里写的话,那么就应该是这样了
Enum.GetName(httpstate,404)
但是模版里的话。。。这个 httpstate 是可以解析了,但如果有多个模版,且枚举类型不一致呢?
比如,有这么个模板内容:
html symbols: ^lt,enum,htmlsymbols^ ^trage,enum,htmlsymbols^ ^gt,enum,htmlsymbols^
http state: ^200.enum.httpstate^ ^403.enum.httpstate^ ^500.enum.httpstate^
bidstate: ^11.enum.trade^ ^91.enum.trade^ ^99.enum.trade^
那么,这里出现了三个枚举类型,如果少的话,不通过反射,用程序一个一个分支,或者 switch 一下,也是可以的,但是,如果再出现新的类型,那么还是很痛苦的,经常需要改代码了。
所以,我们还是通过反射来实现枚举调用。
GetTypeByName(EnumName) 为空?
我们直接使用之前定义的通过类名字符串调用类的方法 GetTypeByName,里面的参数给一个枚举类型。。。结果。。。没有能获取到枚举类型?Type 返回的是 null ??
我连泛型都搞出来了,你告诉我,枚举不能用?
foreach (Type st in ts){if (RegexExpand.IsMatch(st.FullName, @"\." + RegexExpand.FormatRegExp(source) + @"(`?\d+)?$")){return st;}}
打开原来的代码,在 RegexExpand.IsMatch 这一行,老顾打了一个断点,然后,发现枚举Enum 的字符串类型。。。有点哭笑不得。
好么,类的话,FullName 就是 xxx.yyy.zzz 的方式,泛型就是 xxx.yyy.zzz`n 的方式,结果,枚举类型,你给来了个 xxx.yyy+zzz 的方式。。。。
所以,修改起来也非常简单,把刚才代码中的正则 @“\.” 换成 @“[\.+]” 即可。
然后,我们就可以正常的调用枚举处理内容了:
try{Type t = Common.GetTypeByName(枚举类型字符串);return Enum.GetName(t, int.Parse(枚举值));}catch (Exception ex){return ex.Message;}
小结
好吧,没什么可多总结的,就是 FullName 的格式,有点出乎预料,也许,还有其他形式的FullName。总之,还是要多见识见识才好。
另外,再补充一下,直接把 RegexExpand 修改成 Regex 即可,这是老顾自己定义的一个静态类,继承并扩充了一下 Regex 罢了。
FormatRegExp 方法,就是将字符串转成正则表达式,类似 py 中的 re.escape
public static string FormatRegExp(string str){return str.Replace("\\", @"\\").Replace("(", "\\(").Replace(")", "\\)").Replace("{", "\\{").Replace("}", "\\}").Replace("[", "\\[").Replace("]", "\\]").Replace(".", "\\.").Replace("+", "\\+").Replace("-", "\\-").Replace("^", "\\^").Replace("$", "\\$").Replace("?", "\\?").Replace("*", "\\*").Replace("|", "\\|");}
其实,就是几个字符替换的事,自己随便放到哪里都可以。