Smart Enums in C#

Introduction
Smart Enums, as a feature you can use in C#, can help make your code more readable and understandable. Traditionally, an enum type is simply a data type containing a set of constant values. However, Smart Enums add additional functionality to the enum type. For example, a Smart Enum can provide a Parse method used to map a string value to an enum value.
This allows you to specify the enum constant as a string in your code instead of using a specific enum constant. Additionally, Smart Enums can be used to add custom behaviors to enum constants. For instance, a Smart Enum can define specific functions for an enum constant. This can help make your code more readable and understandable. As a result, Smart Enums can greatly improve the quality of your code. Below is an example of Smart Enum C# code:
//SmartEnum class
public abstract class SmartEnum<TEnum, TValue> where TEnum : SmartEnum<TEnum, TValue>
{
private static readonly ConcurrentDictionary<TValue, TEnum> _items =
new ConcurrentDictionary<TValue, TEnum>();
public TValue Value { get; }
public string Name { get; }
protected SmartEnum(TValue value, string name)
{
Value = value;
Name = name;
}
static SmartEnum()
{
// Automatically register all enum values
foreach (var field in typeof(TEnum).GetFields(BindingFlags.Public | BindingFlags.Static))
{
var item = (TEnum)field.GetValue(null);
Register(item);
}
}
public static TEnum FromValue(TValue value)
{
return _items[value];
}
public static bool TryFromValue(TValue value, out TEnum result)
{
return _items.TryGetValue(value, out result);
}
public static IEnumerable<TEnum> GetAll()
{
return _items.Values;
}
protected static TEnum Register(TEnum item)
{
return _items.GetOrAdd(item.Value, item);
}
public override string ToString()
{
return Name;
}
}
//--------------------------------------------------------------
// Gender class which is inherited SmartEnum class
public class Gender : SmartEnum<Gender, string>
{
public static readonly Gender Male = new Gender("M", "Male");
public static readonly Gender Female = new Gender("F", "Female");
public static readonly Gender Unknown = new Gender("U", "Unknown");
public Gender(string value, string name)
: base(value, name)
{
}
}
//--------------------------------------------------------------
// Program.cs
using SmartEnums;
Gender gender = Gender.FromValue("M");
if (gender == Gender.Male)
{
Console.WriteLine("The person is male.");
}
Console.ReadLine();In this example, the SmartEnum class forms the basis of Smart Enums. This class defines the Value and Name properties of Smart Enums. The Register method performs registration for Smart Enums. The FromValue method is a function that takes a value and returns the corresponding Smart Enum constant. The TryFromValue method is the same as FromValue but also checks if a value exists as a Smart Enum. This SmartEnum class provides essential functionality for the implementation of Smart Enums. By understanding and utilizing these methods, developers can create more readable and maintainable code.
Comparison of SmartEnums with Classic Enums
In this section, SmartEnums are compared with Classic Enums on examples and their advantages and disadvantages are discussed. Let’s start!
- Easy management of values: Smart Enums can make enum constants more specialized, adding properties and functions. This makes the difference with enum constants clearer and prevents errors.
//Classic Enum
public enum Gender
{
Male,
Female,
Unknown
}
//Smart Enum
public class Gender : SmartEnum<Gender, string>
{
public static readonly Gender Male = new Gender("M", "Male");
public static readonly Gender Female = new Gender("F", "Female");
public static readonly Gender Unknown = new Gender("U", "Unknown");
private Gender(string value, string name)
: base(value, name)
{
}
}2. Readability: Smart Enums makes enum constants more understandable and readable. The meaning of the constants is clearer and the code is easier to understand.
// Classic
public enum UserRole
{
Admin,
Manager,
Employee
}
//Smart
public class UserRole : SmartEnum<UserRole, int>
{
public static readonly UserRole Admin = new UserRole(1, "Admin");
public static readonly UserRole Manager = new UserRole(2, "Manager");
public static readonly UserRole Employee = new UserRole(3, "Employee");
private UserRole(int value, string name)
: base(value, name)
{
}
}3. Flexibility: By adding properties and functions to enum constants, Smart Enums can create a more flexible structure. This makes the code more modular and increases code reusability.
// Classic
public enum PaymentType
{
CreditCard,
DebitCard,
BankTransfer
}
//Smart
public sealed class PaymentType : SmartEnum<PaymentType, string>
{
public static readonly PaymentType CreditCard = new PaymentType("CC", "Credit Card", new CreditCardPaymentProcessor());
public static readonly PaymentType DebitCard = new PaymentType("DC", "Debit Card", new DebitCardPaymentProcessor());
public static readonly PaymentType BankTransfer = new PaymentType("BT", "Bank Transfer", new BankTransferPaymentProcessor());
private PaymentType(string value, string name, IPaymentProcessor paymentProcessor)
: base(value, name)
{
}
}4. Flexible Values: Smart Enums allow you to define your constant values in a more flexible way. For example, you can define a constant using a value such as text or a date.
public sealed class Colors : SmartEnum<Colors, string>
{
public static readonly Colors Red = new Colors("R", "Red");
public static readonly Colors Green = new Colors("G", "Green");
public static readonly Colors Blue = new Colors("B", "Blue");
private Colors(string value, string name)
: base(value, name)
{
}
}5. Grouping Constants: Smart Enums allows you to group constants. This makes the code more readable and understandable.
// Classic
public enum PizzaType
{
MeatLovers,
Vegetarian,
PineappleLovers
}
//Smart
public sealed class Pizza : SmartEnum<Pizza>
{
public static readonly Pizza Margherita = new Pizza(1, "Margherita", PizzaType.Vegetarian);
public static readonly Pizza Pepperoni = new Pizza(2, "Pepperoni", PizzaType.MeatLovers);
public static readonly Pizza Hawaiian = new Pizza(3, "Hawaiian", PizzaType.PineappleLovers);
public static readonly Pizza MeatLovers = new Pizza(4, "Meat Lovers", PizzaType.MeatLovers);
public static readonly Pizza VeggieLovers = new Pizza(5, "Veggie Lovers", PizzaType.Vegetarian);
public int Id { get; }
public string Name { get; }
public PizzaType Type { get; }
private Pizza(int id, string name, PizzaType type)
{
this.Id = id;
this.Name = name;
this.Type = type;
}
}6. Object Creation: Smart Enums allow you to map your constants to objects. This allows your constants to have properties, methods, and behaviors.
public sealed class Pizza : SmartEnum<Pizza>
{
public static readonly Pizza Margherita = new Pizza(1, "Margherita", 10m);
public static readonly Pizza Pepperoni = new Pizza(2, "Pepperoni", 12m);
public static readonly Pizza Hawaiian = new Pizza(3, "Hawaiian", 15m);
public int Id { get; }
public string Name { get; }
public decimal Price { get; }
private Pizza(int id, string name, decimal price)
{
this.Id = id;
this.Name = name;
this.Price = price;
}
public void PrintDescription()
{
Console.WriteLine($"{this.Name} pizza is {this.Price:C}.");
}
}In summary, the advantages of using Smart Enums are:
- Improved code readability. Smart Enums can be more meaningful and readable than classic enums.
- We can define custom properties and behaviors for enum constants.
- We can treat enum constants as objects, making our code more flexible.
- Security and consistency issues that arise with classic enums are eliminated.
By utilizing Smart Enums, developers can create code that is easier to read, maintain, and understand. Additionally, Smart Enums provide added flexibility and customizability, making them a valuable tool in any development project. Smart Enums are also particularly useful in the following situations:
- Enum constants are to be used together with their properties and behaviors.
- The values of constants are calculated at runtime or determined dynamically.
- We want to guarantee the correctness and consistency of the constants.
If you ask if there are no disadvantages besides all these advantages, of course, there are. These are below;
- Limited support: Smart Enums is considered a feature that is not directly supported by the C# language. Therefore, its usability in other languages other than C# is limited.
- Learning curve: Smart Enums, unlike classic enums, require a learning curve. This can make the learning process a bit more difficult for beginners.
- Performance: Smart Enums may require slightly more computation and memory usage. This can affect the performance of applications.
And so I come to the end of another article. I wish you a day with Smart Enums :)






