Enhancing Enum Handling in Spargine: Beyond Enums and into Versatility

Spargine is a collection of open-source assemblies and NuGet packages designed for .NET 10, which I have been developing and maintaining since the release of .NET Framework 2. These assemblies are not only a core part of my projects but are also actively deployed in production environments across several companies I collaborate with.

Get Spargine

You can access the source code and NuGet packages here:

In programming, Enums are a powerful way to represent a fixed set of related constants. They improve readability, eliminate “magic numbers,” and make code easier to understand and maintain. For years, I’ve relied on Enums to provide user-friendly values in dropdowns, configuration settings, and UI selections.

However, there is a common anti-pattern I strongly recommend avoiding: using Enum values as a lookup mechanism to retrieve display names from a database. While it may seem convenient, it introduces unnecessary coupling and can create performance bottlenecks. Enums should describe state and intent—not serve as database keys for user-facing strings.

This article walks through how Spargine makes working with Enums simpler and more efficient using EnumHelper and EnumExtensions. Then we take it a step further by showing how to move beyond traditional Enums entirely using the Enumeration pattern for scenarios where Enums reach their limits.

Utilizing EnumHelper: Simplifying Enum Handling

EnumHelper centralizes common Enum operations into a fast, reusable API. It removes boilerplate reflection code and ensures consistent behavior across your applications.

Currently, EnumHelper provides the following methods:

  • GetDescription(this Enum input)
    Gets the description of the enum value by checking multiple attributes in this order: DescriptionAttribute, EnumMemberAttribute, the enum’s name as a fallback
  • GetItems<T>(bool fixNames)
    Gets the enumeration names and values for a specified enumeration type. If fixNames is set to true, it adjusts the names for readability by adding spaces in camel case names and replacing underscores with spaces.
  • TryParse<T>(string name, out T result)
    Attempts to parse the specified name into an enum value.

Usage Examples

GetDescription()

var result = EnumHelper.GetDescription(Status.NotSet)

Output:

Not Set

GetItems()

var values = EnumHelper.GetItems<Status>();

Output:

[0]: {EnumValue { Name = Not Set, Value = 0 }}
[1]: {EnumValue { Name = New, Value = 1 }}
[2]: {EnumValue { Name = Available, Value = 2 }}
[3]: {EnumValue { Name = Not Used, Value = 3 }}
[4]: {EnumValue { Name = Obsolete, Value = 4 }}
[5]: {EnumValue { Name = Updated, Value = 5 }}
[6]: {EnumValue { Name = Needs Documentation, Value = 6 }}
[7]: {EnumValue { Name = Update Documentation, Value = 7 }}

Harnessing the Power of EnumExtensions

EnumExtensions builds on EnumHelper and exposes its capabilities as clean extension methods. This removes repetitive helper calls and makes your code more expressive.

Available methods:

  • FlagCount
    Gets the count of flags set in a flag enum.
  • GetAttribute<TAttribute>() 
    Gets the custom attribute of type applied to the enum value.
  • GetDescription()
    Gets the description of the enum value.
  • GetDisplayName()
    Gets the display name from the DisplayAttribute if present; otherwise returns the enum’s name.
  • GetItems()
    Gets the names and values of an Enum. This method returns a read-only collection of tuples, where each tuple contains the name (description) and the numeric value of each enum member.
  • GetSetFlags()
    Gets the individual flag values that are set in a flag enum.
  • Next()
    Gets the next enum value in sequence, or the first value if at the end.
  • Parse<T>(this string name)
    Parses the specified string to an enum.
  • Previous()
    Gets the previous enum value in sequence, or the last value if at the beginning.
  • ToInt32()
    Gets the 32-bit integer value of the enum.
  • ToInt64()
    Gets the 64-bit integer value of the enum.

Together, EnumHelper and EnumExtensions drastically reduce friction when working with Enums and eliminate repetitive reflection logic throughout your codebase.

Go Beyond Enums

Traditional Enums have limitations:

  • No inheritance
  • No behavior
  • Fixed values at compile time
  • Limited extensibility

In 2021, Jimmy Bogard popularized the Enumeration pattern as a way to overcome these constraints. I adopted and integrated this approach into Spargine.

In Spargine, Enumeration is implemented as an abstract record, giving you:

  • Strong typing
  • Built-in equality
  • Extensibility
  • Rich behavior

Example Implementation

public record DateTimeFormat : Enumeration
{
    public static readonly DateTimeFormat FullDateLongTime = new(0, "F");

    public static readonly DateTimeFormat FullDateShortTime = new(1, "f");

    // Code removed for brevity
}

Now your “enum” values can:

  • Have behavior
  • Expose methods
  • Carry metadata
  • Participate in richer domain logic

Usage example:

var result = now.ToFormattedString(DateTimeFormat.FullDateLongTime);

This approach completely transcends what traditional Enums can do while preserving clarity and safety.

Summary

Enums are a foundational tool in .NET, but they are often misused—especially when they become indirect database keys for display text. That practice introduces unnecessary coupling and performance risks.

In this article, you saw how Spargine improves Enum usability through:

  • EnumHelper for centralized, high-performance Enum operations
  • EnumExtensions for expressive, extension-based access
  • The Enumeration pattern for scenarios that demand greater flexibility

When Enums are enough, Spargine makes them easy.
When Enums fall short, Spargine gives you a better model.

That’s what real versatility looks like.

I hope you’ll start using these Spargine features to simplify your Enum handling and elevate your design. As always, I welcome your feedback and insights in the comments.

Get Involved!

The success of open-source projects like Spargine relies on community contributions. If you find these updates useful or have ideas for further improvements, I encourage you to contribute by:

  • Submitting pull requests
  • Reporting issues
  • Suggesting new features

Your input is invaluable in making Spargine an even more powerful tool for the .NET community.

If you are interested in contributing or have any questions, feel free to contact me via email at dotnetdave@live.com. Your support and collaboration are greatly appreciated!

Thank you, and happy coding!

Pick up any books by David McCarter by going to Amazon.com: http://bit.ly/RockYourCodeBooks

One-Time
Monthly
Yearly

Make a one-time donation

Make a monthly donation

Make a yearly donation

Choose an amount

$5.00
$15.00
$100.00
$5.00
$15.00
$100.00
$5.00
$15.00
$100.00

Or enter a custom amount

$

Your contribution is appreciated.

Your contribution is appreciated.

Your contribution is appreciated.

DonateDonate monthlyDonate yearly

If you liked this article, please buy David a cup of Coffee by going here: https://www.buymeacoffee.com/dotnetdave

© The information in this article is copywritten and cannot be preproduced in any way without express permission from David McCarter.


Discover more from dotNetTips.com

Subscribe to get the latest posts sent to your email.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.