Ardalis.SmartEnum
repository·main·Indexed 25 days ago
https://github.com/ardalis/smartenumA type-safe, object-oriented alternative to standard C# enums that allows developers to attach data and behavior to enum members. It supports custom value types, inheritance for polymorphic behavior, and bitwise flags via SmartFlagEnum. The library includes specialized sub-packages for integration with EF Core, Dapper, AutoFixture, and various serialization formats including System.Text.Json, Json.NET, MessagePack, ProtoBufNet, and Utf8Json.
What's inside Ardalis.SmartEnum
- SmartEnum is a type-safe, object-oriented alternative to standard C# enums. It allows you to define enums as classes, enabling you to attach additional properties and behavior to each enum member.
Implement bitwise flags with SmartFlagEnum
mainFor flag-like behavior, inherit from
SmartFlagEnum<TEnum>.Requirements:
- Values must be powers of two (1, 2, 4, 8, etc.). If they are not, a
SmartFlagEnumDoesNotContainPowerOfTwoValuesExceptionis thrown. You can bypass this with[AllowUnsafeFlagEnumValues], but the enum may not behave as expected. - You can define explicit
Combinationvalues (e.g.,CardAndCash = 3) which will be returned byFromValue()instead of the individual flags. - A value of
-1passed toFromValue()returns anIEnumerablecontaining all values (excluding 0).
Key Methods:
FromValue(TValue value): Returns anIEnumerable<TEnum>containing all matching flags.FromName(string names): Accepts a comma-separated string of names and returns anIEnumerable<TEnum>.FromValueToString(TValue value): Returns a comma-separated string of the names of the matching flags.
public class SmartFlagTestEnum : SmartFlagEnum<SmartFlagTestEnum> { public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0); public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1); public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2); public static readonly SmartFlagTestEnum CardAndCash = new SmartFlagTestEnum(nameof(CardAndCash), 3); public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4); public SmartFlagTestEnum(string name, int value) : base(name, value) { } } // Usage var result = SmartFlagTestEnum.FromValue(3); // Returns Card and Cash var names = SmartFlagTestEnum.FromValueToString(3); // "Card, Cash"- Values must be powers of two (1, 2, 4, 8, etc.). If they are not, a
Add behavior to a SmartEnum using inheritance
mainUnlike standard enums, SmartEnums can use inheritance to attach properties or methods to specific enum members. This allows you to replace
switchstatements with polymorphic behavior. You define an abstract base class and private sealed classes for each enum member that override the abstract members.using Ardalis.SmartEnum; public abstract class EmployeeType : SmartEnum<EmployeeType> { public static readonly EmployeeType Manager = new ManagerType(); public static readonly EmployeeType Assistant = new AssistantType(); private EmployeeType(string name, int value) : base(name, value) { } public abstract decimal BonusSize { get; } private sealed class ManagerType : EmployeeType { public ManagerType() : base("Manager", 1) {} public override decimal BonusSize => 10_000m; } private sealed class AssistantType : EmployeeType { public AssistantType() : base("Assistant", 2) {} public override decimal BonusSize => 1_000m; } }Configure AutoFixture support for SmartEnum
mainBy default, AutoFixture attempts to create new instances of types. Since
SmartEnuminstances should always be references to existing ones, use theArdalis.SmartEnum.AutoFixturepackage. You can integrate it by adding theSmartEnumCustomizationto yourIFixturebuilder.var fixture = new Fixture() .Customize(new SmartEnumCustomization()); var smartEnum = fixture.Create<TestEnum>();Define a SmartEnum with a custom value type
mainYou can specify a different type for the enum's value (e.g.,
ushort,long,string) by providing a second generic argument toSmartEnum<TEnum, TValue>.using Ardalis.SmartEnum; public sealed class TestEnum : SmartEnum<TestEnum, ushort> { public static readonly TestEnum One = new TestEnum("A string!", 1); public static readonly TestEnum Two = new TestEnum("Another string!", 2); public static readonly TestEnum Three = new TestEnum("Yet another string!", 3); private TestEnum(string name, ushort value) : base(name, value) { } }Install Ardalis.SmartEnum.GuardClauses
mainTo use the guard clauses for SmartEnum validation, install the package via NuGet Package Manager Console or the .NET CLI.Enable Dapper support for SmartEnum
mainTo allow Dapper to map
SmartEnumvalues to database columns, you must register a type handler withSqlMapper.- Use
SmartEnumByNameTypeHandler<T>to map the Name of the enum to a database column. - Use
SmartEnumByValueTypeHandler<T>to map the Value of the enum to a database column.
// Maps the name of TestEnum objects (e.g. "One", "Two", or "Three") to a database column. SqlMapper.AddTypeHandler(typeof(TestEnum), new SmartEnumByNameTypeHandler<TestEnum>());// Maps the value of TestEnum objects (e.g. 1, 2, or 3) to a database column. SqlMapper.AddTypeHandler(typeof(TestEnum), new SmartEnumByValueTypeHandler<TestEnum>());- Use
Install Ardalis.SmartEnum via NuGet
mainTo use SmartEnum, install the base package via NuGet. Depending on your requirements for serialization or ORM support, you may also need to install specific sub-packages.
Base Package:
Install-Package Ardalis.SmartEnumAdditional Support Packages:
Ardalis.SmartEnum.AutoFixtureArdalis.SmartEnum.JsonNetArdalis.SmartEnum.SystemTextJsonArdalis.SmartEnum.Utf8JsonArdalis.SmartEnum.MessagePackArdalis.SmartEnum.ProtoBufNetArdalis.SmartEnum.EFCoreArdalis.SmartEnum.ModelBindingArdalis.SmartEnum.Dapper
Install-Package Ardalis.SmartEnumPersist SmartEnum with EF Core
mainTo persist SmartEnums in EF Core, you must map the enum to its underlying value type using value conversions.
Manual Configuration (EF Core 2.1+)
Use
HasConversioninOnModelCreatingto map the property to itsValueand useFromValueto reconstruct it.Note: You must implement a parameterless constructor in your SmartEnum class for EF Core to work correctly.
builder.Entity<Policy>() .Property(p => p.PolicyStatus) .HasConversion( p => p.Value, p => PolicyStatus.FromValue(p));Automatic Configuration (using Ardalis.SmartEnum.EFCore)
If you have the
Ardalis.SmartEnum.EFCorepackage installed, you can use pre-convention configuration.EF Core 6+:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder.ConfigureSmartEnum(); }EF Core < 6:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ConfigureSmartEnum(); }// EF Core 6+ example protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) { configurationBuilder.ConfigureSmartEnum(); }Define a basic SmartEnum
mainTo create a smart enum, inherit from
SmartEnum<TEnum>. You must define static readonly instances of your enum and provide a private constructor that calls the base constructor with a name and a value. By default, the value type isint.using Ardalis.SmartEnum; public sealed class TestEnum : SmartEnum<TestEnum> { public static readonly TestEnum One = new TestEnum(nameof(One), 1); public static readonly TestEnum Two = new TestEnum(nameof(Two), 2); public static readonly TestEnum Three = new TestEnum(nameof(Three), 3); private TestEnum(string name, int value) : base(name, value) { } }Configure System.Text.Json serialization for SmartEnum
mainTo control whether a
SmartEnumis serialized using itsNameor itsValueinSystem.Text.Json, use theArdalis.SmartEnum.SystemTextJsonpackage. Apply the appropriate converter attribute to the property in your model.- Use
SmartEnumNameConverter<TEnum, TValue>to serialize/deserialize using the Name. - Use
SmartEnumValueConverter<TEnum, TValue>to serialize/deserialize using the Value.
public class TestClass { [JsonConverter(typeof(SmartEnumNameConverter<TestEnum,int>))] public TestEnum Property { get; set; } }- Use
Configure Json.NET serialization for SmartEnum
mainTo control whether aSmartEnumis serialized using itsNameor itsValueinJson.NET, use theArdalis.SmartEnum.JsonNetpackage. Apply the appropriate converter attribute to the property in your model.