Enums – Better syntax, improved performance and TryParse in NET 3.5
- 📅
- 📝 495 words
- 🕙 3 minutes
- 📦 .NET
- 🏷️ C#
- 💬 10 responses
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 with 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 with Enum<T>
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;
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<MyEnumbers>.GetName(a)
overa.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 to Enums – Better syntax, improved performance and TryParse in NET 3.5
Hi, As I said previously i find your helper nice, but (IMHO) there were a few leaks.
so I improved it a little bit.
Here you may find my version, fully tested with below NUnit test (sorry, comments are in french) :
Hope this would help somebody. Regards Richard
Great work ! Just noticed in little difference against original enum methods : original “Parse” performs a Trim() on processed value. Your version doesn’t.
Nice one Damo — just used this in a project, really nice idea. Hope all’s well Stateside :-)
Oh, I see.
But you can wrap your class by there methods for using syntax sugar and not duplicate caches :)
The problem with doing it that way is that you’d end up having to duplicate the cache per method…
Unless the
Enum.
methods were just proxies back toEnum<T>
...Useful class, but instead of
Enum<T>
useEnum.Method<T>
and you can use syntax sugar with it. Compiler can automatically recognize type parameters of methods not a classesExample:
Cheers.
I took a similar approach creating a Enum type and created a bunch of common helper methods for parsing/converting enum values. The funny thing is that you get so used to the API, that you begin to think that it’s native to .net after awhile…well at least you wish it was native to .net!
Thanks for sharing.
-Jeff
I thought about writing a “How it works” section but decided against it.
But yes, that’s pretty much it :)
Thanks; this is really useful! Interesting technique: You’re taking advantage of generic instantiation to populate a cache for each distinct enum type.
No love for flag enums? Looks like a useful class otherwise, thanks