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
- Why do I have to the cast results back to MyEnum all the time?
- Can I write
TryParseand 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.
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);
var 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;
GitHub has the latest version of EnumT.cs
- 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
CastOrNullfunction instead of just putting (T)
GetNameis actually much quicker than
ToStringon 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.IsDefinedcan 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.