Enums – Better syntax, improved performance and TryParse in NET 3.5
Recently I needed to map external data into in-memory objects. In such scenarios the TryParse methods of Int and String are useful but where is Enum.TryParse? TryParse exists in .NET 4.0 but like a lot of people I’m on .NET 3.5.
A quick look at Enum left me scratching my head.
- Why didn’t enums receive the generic love that collections received in .NET 2.0?
- Why do I have to pass in
typeof(MyEnum)
everywhere? - Why do I have to the cast results back to MyEnum all the time?
- Can I write
TryParse
and still make quick – i.e. without try/catch?
I found myself with a small class, Enum<T>
that solved all these. I was surprised when I put it through some benchmarks that also showed the various methods were significantly faster when processing a lot of documents. Even my TryParse was quicker than that in .NET 4.0.
While there is some small memory overhead with the initial class (about 5KB for the first, a few KB per enum after) the performance benefits came as an additional bonus on top of the nicer syntax.
Before (System.Enum)
var getValues = Enum.GetValues(typeof(MyEnumbers)).OfType();
var parse = (MyEnumbers)Enum.Parse(typeof(MyEnumbers), "Seven");
var isDefined = Enum.IsDefined(typeof(MyEnumbers), 3);
var getName = Enum.GetName(typeof(MyEnumbers), MyEnumbers.Eight);
MyEnumbers tryParse;
Enum.TryParse<MyEnumbers>("Zero", out tryParse);
)
After (Enumvar getValues = Enum<MyEnumbers>.GetValues();
var parse = Enum<MyEnumbers>.Parse("Seven");
var isDefined = Enum<MyEnumbers>.IsDefined(MyEnumbers.Eight);
var getName = Enum<MyEnumbers>.GetName(MyEnumbers.Eight);
MyEnumbers tryParse;
Enum<MyEnumbers>.TryParse("Zero", out tryParse);
I also added a useful ParseOrNull
method that lets you either return null or default using the coalesce so you don’t have to mess around with out parameters, e.g.
MyEnumbers myValue = Enum<MyEnumbers>.ParseOrNull("Nine-teen") ?? MyEnumbers.Zero;
The class
GitHub has the latest version of EnumT.cs
Usage notes
- This class as-is only works for Enum’s backed by an int (the default) although you could modify the class to use longs etc.
- I doubt very much this class is of much use for flag enums
- Casting from long can be done using the
CastOrNull
function instead of just putting (T) GetName
is actually much quicker thanToString
on the Enum… (e.g. Enum.GetName(a) over a.ToString()) - IsDefined doesn’t take an object like Enum and instead has three overloads which map to the actual types
Enum.IsDefined
can deal with and saves run-time lookup - Some of the method may not behave exactly like their Enum counterparts in terms of exception messages, nulls etc.
[)amien
10 responses