- Frugal Cafe
- Posts
- FC30: Your code base needs an EnumHelper<T> class
FC30: Your code base needs an EnumHelper<T> class
Bag of performance issues in Enum type
In C#, Enum types are commonly used, but it has quite a few performance issues. The common issues are GetHashCode/HasFlags would cause boxing. The most expensive issues are Enum.ToString and Enum.Parse implementation. So lots of code bases I’ve seen have helper classes and extension methods to deal with such issues. But due to the complexity of Enum type normal developers are not even aware of, there could be lots of issues in such helper classes and extension methods.
The GetHashCode issue is easy to fix, you can just cast to integer. HasFlags is normally replaced with extension methods using bit masking operations.
For constant values, you can just use nameof(identifier). For variables, let’s deal with Enum.ToString issue with a generic helper class.
Here is the data structure and constructor:
We have a static shared instance, a delegate to convert to 64-bit integer, a fast lookup string array, and an optional concurrent dictionary for overflows.
Here is the fast ToString implementation:
The delegate is used to convert enum value to integer. We then check the string array. If the index is within its range but value is missing, the value is written back. This handles the flag case when multiple flags are used.
When the value is outside of the string array range, we use concurrent dictionary for caching. But there could be millions of such values/strings, so we clear the dictionary when it’s getting too big, to avoid memory overblown.
Here is the delegate generation code:
Performance tests:
Results (.Net Framework 4.8.1):
EnumHelper reduces 98% cost, 50x faster than mscorlib implementation, without any heap allocation.
The implementation in .Net Core has been improved, but this EnumHelper class is still better.