本文核心代码来自网上现有的C#代码,稍稍改了一下,所以不做原创发布。
下面例子中定义的枚举,既可以在程序内部使用枚举定义的枚举名或者枚举值,又可以向用户展示枚举的描述值,可以避免使用中文来定义枚举的尴尬以及可能会带来的未知bug。
先来几张不需要说明的图片,能看懂为啥要放这些图片就看,看不懂就怪我咯!~
代码正式开始
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Module Module1
''' <summary>
''' 指定筛选模式
''' </summary>
Public Enum ReleFieldMode
<Description("不限")>
None
<Description("店铺名称")>
Title
<Description("旺旺名称")>
WangWang
End Enum
Sub Main()
For Each enumItem As ReleFieldMode In System.Enum.GetValues(GetType(ReleFieldMode))
Console.WriteLine("枚举名:" & enumItem.ToString() & " 枚举值:" & enumItem & " 描述:" & enumItem.GetDescription)
Next
Console.ReadKey()
End Sub
''' <summary>
''' 利用反射获取枚举项的描述
''' </summary>
''' <param name="enumItem"></param>
''' <returns></returns>
<Extension()>
Public Function GetDescription(ByVal enumItem As System.Enum) As String
If enumItem Is Nothing Then Return String.Empty
' #########扩展方法必须要放到模块(Module)中#########
' 利用反射获取枚举项的描述
Dim enumItemName = enumItem.ToString()
Dim enumItemType = enumItem.GetType()
Dim fieldinfo = enumItemType.GetField(enumItemName)
Dim obj = fieldinfo.GetCustomAttributes(GetType(DescriptionAttribute),False)
If obj.Length = 0 Then
Return String.Empty
Else
Dim desc = DirectCast(obj.First,DescriptionAttribute)
Return desc.Description
End If
End Function
End Module
效果:
另外放一些跟反射相关的图片
测试环境:VS2017 & Win7 64 & .NET Framework4.5.2
20170429更新
修复无法正确获取到多态枚举项的描述的问题
另外,增加一个判断条件,条件为:
枚举必须按照建议定义None和All项,否则一律返回空值
''' <summary>
''' 通过反射得到单个枚举项的描述
''' 如果获取多个枚举项的描述,需要用Multiple版本,否则无法正确获取
''' </summary>
''' <param name="enumItem"></param>
''' <returns></returns>
<Extension()>
Public Function GetDescriptionSingle(ByVal enumItem As System.Enum) As String
Dim funcResult = String.Empty
Dim enumItemType = enumItem.GetType()
Dim enumItemName = enumItem.ToString()
Dim fieldinfo = enumItemType.GetField(enumItemName)
' 如果enumItemName是多态枚举值或者是未找到符合指定要求的字段的对象,将返回nothing
If fieldinfo Is Nothing Then
Return funcResult
End If
Dim obj = fieldinfo.GetCustomAttributes(GetType(System.ComponentModel.DescriptionAttribute),False)
If obj.Length = 0 Then
Return funcResult
Else
Dim descriptionAttribute = DirectCast(obj.First,System.ComponentModel.DescriptionAttribute)
If descriptionAttribute Is Nothing Then
Return funcResult
End If
funcResult = descriptionAttribute.Description
End If
Return funcResult
End Function
''' <summary>
''' 利用反射获取多个枚举项的描述
''' 如果获取单个枚举项的描述,用Single版本会更高效
''' 如果枚举类没有按照建议的格式来定义,则返回空值
''' 建议None定义为0,与All同时被定义到枚举项中
''' </summary>
''' <param name="enumItems">如果为Nothing,则返回空值</param>
''' <returns></returns>
<Extension()>
Public Function GetDescriptionMultiple(ByVal enumItems As System.Enum) As String
If enumItems Is Nothing Then Return String.Empty
' 如果枚举类没有按照建议的格式来定义,则返回空值
' 建议None定义为0,与All同时被定义到枚举项中
If Not System.Enum.IsDefined(enumItems.GetType,"None") OrElse
Not System.Enum.IsDefined(enumItems.GetType,"All") Then
Return String.Empty
End If
' 利用反射获取枚举项的描述
' 先把enumItems中包含的所有枚举项提取出来到数组中
' 如果有更高效的集合类,可以替换数组,因为用数组要不断ReDim Preserve
Dim enumValues = System.Enum.GetValues(enumItems.GetType())
Dim tempEnumItems As System.Enum() = {}
Dim itemIndex = 0
For Each item As System.Enum In enumValues
If enumItems.HasFlag(item) Then
ReDim Preserve tempEnumItems(itemIndex)
tempEnumItems(itemIndex) = item
itemIndex += 1
End If
Next
' 然后判断数组的长度,如果大于1,那就是enumItems中不包含枚举值None项和All项(通常None定义为0,一般会与All同时被定义到枚举项中)
Dim sb As StringBuilder = StringBuilderCache.Acquire(100)
Dim splitString = ","
If tempEnumItems.Length > 1 Then
For Each enumItem In tempEnumItems
If enumItem.Equals(System.Enum.Parse(enumItems.GetType,"None",True)) OrElse
enumItem.Equals(System.Enum.Parse(enumItems.GetType,"All",True)) Then
Continue For
End If
sb.Append(String.Concat(enumItem.GetDescriptionSingle(),splitString))
Next
Else
sb.Append(String.Concat(tempEnumItems(0).GetDescriptionSingle(),splitString))
End If
' 去掉最后的"," 从后面往前面判断
If sb.Length > 0 AndAlso
sb.Chars(sb.Length - 2).Equals(splitString.Chars(0)) AndAlso
sb.Chars(sb.Length - 1).Equals(splitString.Chars(1)) Then
sb.Remove(sb.Length - splitString.Length,splitString.Length)
End If
Return StringBuilderCache.GetStringAndRelease(sb)
End Function
噢,上面用到的StringBuilderCache类,你们改成StringBuilder类相应的方法就可以了。
测试枚举定义(含有Flags标识,可以对枚举项进行位运算)
测试结果