One thing I’ve begun to notice about VB.NET is that there are a pile of options as to how you might implement a particular piece of functionality. I’m still not convinced that this is necessarily a good thing, but it is hard to argue with having options.
For instance, I recently needed a function to retrieve the number of elements defined in an enumeration. Now, I realize that enumerations can be sparse, and that creating an array to be indexed by the enumeration values will not work with all enumerations, but that’s a topic for another post.
The first option I thought of was to implement it as a plain ol’ function in a module:
Debug.print GetEnumItemCount(GetType(MyEnum))
Public Function GetEnumItemCount(ByVal typ As Type) As Integer
If typ.IsEnum Then
Return System.Enum.GetNames(typ).Length
Else
Return 0
End If
End Function
Not terribly interesting and it’s perfectly functional, but it just doesn’t seem particularly .NET-ish. Also, I don’t really care for the “double function” approach (ie calling GetType() to retrieve the enum type descriptor object to pass into the function).
So, any way to improve this?
One way is to get rid of the extra GetType function call. Unfortunately, the only way I’ve seen to do this so far is to pass in one of the enumeration values instead of the enumeration itself (or its type).
Debug.print GetEnumSiblingCount(MyEnum.Value1)
Public Function GetEnumSiblingCount(ByVal e As [Enum]) As Integer
Return System.Enum.GetNames(e.GetType).Length
End Function
I’ve renamed the function GetEnumSiblingCount because that’s exactly what this new function does, return the total number of siblings to the passed in enumeration element.
Unfortunately, this approach still seems a little a lot odd.
My next thought was, why not add an extension method to the enumeration itself, so you could do something like:
Debug.print MyEnum.Count
Unfortunately, since MyEnum is a type and not considered an actual object in any sense, you can’t invoke a method on it, or even define one on it for that matter.
You can, however, get close, by defining an extension method on the Type object itself:
Debug.Print GetType(MyEnum).Count
Module EnumExtender
<extension ()> _
Public Function Count(ByVal typ As Type) As Integer
If typ.IsEnum Then
Return System.Enum.GetNames(typ).Length
Else
Return 0
End If
End Function
End Module
The downside here is that we’re extending not just enum types but all types, and extending anything other than enums with this function doesn’t make much sense.
Interestingly, there’s yet another option; extend the enum elements themselves.
Debug.print MyEnum.Value1.SiblingCount
Module EnumExtender
<extension ()> _
Public Function SiblingCount(ByVal anEnum As [Enum]) As Integer
Return System.Enum.GetNames(anEnum.GetType).Count
End Function
End Module
However, this also has the same problem as a previous try in that it just doesn’t feel right to ask an enumeration element for some property of it’s containing type.
Ok, how about just changing up the definition of the enumeration itself:
Public Enum MyEnum
Value1 = 0
Value2 = 1
Value3 = 2
Count = 3
End enum
Short, sweet, no compiler tricks or reflection.
But. It doesn’t work with existing, already defined Enumerations, and since the Count is part of the enumeration, the actual count of the enum is 4, not 3, which would seem to be confusing in the long run.
I’m sure there’s many more possibilities as well, and, hopefully, I’ve missed a better one and someone out there will let me know it!
Long story short, my first inclination, the plain ol’ function-in-a-module GetEnumItemCount(), seems the best solution for this particular piece of functionality.
In reality, the best solution for most of these sorts of generic, application-wide, stateless utility functions seems to be the plain ol’ function-in-a-module.