LightPoint.Foundation.SmartEnum.EFCore 1.2.0

dotnet add package LightPoint.Foundation.SmartEnum.EFCore --version 1.2.0
NuGet\Install-Package LightPoint.Foundation.SmartEnum.EFCore -Version 1.2.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LightPoint.Foundation.SmartEnum.EFCore" Version="1.2.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add LightPoint.Foundation.SmartEnum.EFCore --version 1.2.0
#r "nuget: LightPoint.Foundation.SmartEnum.EFCore, 1.2.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install LightPoint.Foundation.SmartEnum.EFCore as a Cake Addin
#addin nuget:?package=LightPoint.Foundation.SmartEnum.EFCore&version=1.2.0

// Install LightPoint.Foundation.SmartEnum.EFCore as a Cake Tool
#tool nuget:?package=LightPoint.Foundation.SmartEnum.EFCore&version=1.2.0

简要说明

Smart Enum 是一种编程概念,通常在现代编程语言中作为一种增强的枚举(Enumeration)实现。传统的枚举类型允许开发者定义一组命名的常量,这些常量通常是整数或者其对应的字符串表示。然而,Smart Enum 提供了额外的功能和便利性,使得枚举类型更加易于使用和管理。以下是一些 Smart Enum 可能包含的特性:

  1. 方法和行为

    • Smart Enum 可能包含自定义的方法和行为,使得枚举值不仅仅是简单的常量。例如,一个代表颜色的 Smart Enum 可能包含一个 toString() 方法,返回该颜色的可读字符串表示。
  2. 类型安全

    • Smart Enum 通过编译时检查提供更强的类型安全。尝试将一个枚举类型的值赋给另一个不同类型的枚举会引发编译错误。
  3. 构造函数和初始化

    • Smart Enum 可能具有自定义的构造函数,允许在创建枚举值时进行一些初始化操作或验证。
  4. 元数据和附加信息

    • 每个 Smart Enum 值可以关联额外的信息或元数据。例如,一个代表日期星期的枚举可能包含每个星期几的英文名称和缩写。
  5. 隐式转换和运算符重载

    • 在某些语言中,Smart Enum 可能支持隐式转换为其他类型(如整数或字符串)或重载运算符以支持更自然的表达式。
  6. 集合和迭代

    • Smart Enum 类型可能提供内置的支持,以便轻松地创建包含所有枚举值的集合,并能够迭代这些值。
  7. 反射和运行时查询

    • Smart Enum 可能支持反射机制,允许在运行时查询枚举类型的元数据、枚举值及其相关属性。

本项目是对 C# enum 的 Smart Enum 方式的具体实现,相关的具体资料,可参见: 针对 C# enum类型安全的面向对象替代方案

本项目是参考 Steve Smith 的 SmartEnum 的项目来具体实现的。

使用说明

继承 SmartEnum<TEnum> 来定义一个智能枚举,其中 TEnum 就是所定义的枚举的类型,例如

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)
    {
    }
}

上面的定义中,枚举项的值默认是 int,不过也可以通过第二个泛型参数 TValue 设置成其它的类型。另外,枚举项的名称可以使用明确的字符串值来替换 nameof(One) ,名称可以包含空格,如下所示:

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)
    {
    }
}

与标准的 enum 相同, 多个字符串名称可以赋值给一个值,但相同的字符串名称,不允许赋值给多个不同的值,如下所示:

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);
    public static readonly TestEnum AnotherThree = new TestEnum(nameof(AnotherThree), 3);
    // public static TestEnum Three = new TestEnum(nameof(Three), 4); -> 这个会抛出异常

    private TestEnum(string name, int value) : base(name, value)
    {
    }
}

在上面的示例中, TestEnum.FromValue(3) 将返回所有关联条目(实例)中的第一个, 在未做排序的情况下,返回 TestEnum.Three 或者 TestEnum.AnotherThree

Value 的内容还将用于两个枚举的比较,比较时忽略 Name ,如下所示

TestEnum.One.Equals(TestEnum.One);            // 返回 true
TestEnum.One.Equals(TestEnum.Three);          // 返回 false
TestEnum.Three.Equals(TestEnum.AnotherThree); // 返回 true

继承的智能枚举还可以添加所谓的“行为”,下面的例子就是添加了一个 BonusSize,用来避免常规枚举所典型处理的 switch 的用法。

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;
    }
}

You can take this a step further and use the ManagerType and associated BonusSize property in a parent class like so: 还可以更进一步,在父类中使用 “ManagerType” 和关联的 “BonusSize” 属性,如下所示:

public class Manager
{
    private ManagerType _managerType { get; set; }
    public string Type
    {
        get => _managerType.Name;
        set
        {
            if (!ManagerType.TryFromName(value, true, out var parsed))
            {
                throw new Exception($"Invalid manage type of '{value}'");
            }
            _managerType = parsed;
        }
    }

    public string BonusSize
    {
        get => _managerType.BonusSize();
        set => _bonusSize_ = value;
    }
}

This other example implements a state machine. The method CanTransitionTo() returns true if it's allowed to transition from current state to next; otherwise returns false.

using Ardalis.SmartEnum;

public abstract class ReservationStatus : SmartEnum<ReservationStatus>
{
    public static readonly ReservationStatus New = new NewStatus();
    public static readonly ReservationStatus Accepted = new AcceptedStatus();
    public static readonly ReservationStatus Paid = new PaidStatus();
    public static readonly ReservationStatus Cancelled = new CancelledStatus();

    private ReservationStatus(string name, int value) : base(name, value)
    {
    }

    public abstract bool CanTransitionTo(ReservationStatus next);

    private sealed class NewStatus: ReservationStatus
    {
        public NewStatus() : base("New", 0)
        {
        }

        public override bool CanTransitionTo(ReservationStatus next) =>
            next == ReservationStatus.Accepted || next == ReservationStatus.Cancelled;
    }

    private sealed class AcceptedStatus: ReservationStatus
    {
        public AcceptedStatus() : base("Accepted", 1)
        {
        }

        public override bool CanTransitionTo(ReservationStatus next) =>
            next == ReservationStatus.Paid || next == ReservationStatus.Cancelled;
    }

    private sealed class PaidStatus: ReservationStatus
    {
        public PaidStatus() : base("Paid", 2)
        {
        }

        public override bool CanTransitionTo(ReservationStatus next) =>
            next == ReservationStatus.Cancelled;
    }

    private sealed class CancelledStatus: ReservationStatus
    {
        public CancelledStatus() : base("Cancelled", 3)
        {
        }

        public override bool CanTransitionTo(ReservationStatus next) =>
            false;
    }
}

List

You can list all of the available options using the enum's static List property:

foreach (var option in TestEnum.List)
    Console.WriteLine(option.Name);

List returns an IReadOnlyCollection so you can use the Count property to efficiently get the number of available options.

var count = TestEnum.List.Count;

FromName()

Access an instance of an enum by matching a string to its Name property:

var myEnum = TestEnum.FromName("One");

Exception SmartEnumNotFoundException is thrown when name is not found. Alternatively, you can use TryFromName that returns false when name is not found:

if (TestEnum.TryFromName("One", out var myEnum))
{
    // use myEnum here
}

Both methods have a ignoreCase parameter (the default is case sensitive).

FromValue()

Access an instance of an enum by matching its value:

var myEnum = TestEnum.FromValue(1);

Exception SmartEnumNotFoundException is thrown when value is not found. Alternatively, you can use TryFromValue that returns false when value is not found:

if (TestEnum.TryFromValue(1, out var myEnum))
{
    // use myEnum here
}

ToString()

Display an enum using the ToString() override:

Console.WriteLine(TestEnum.One); // One

Switch

Given an instance of a TestEnum, switch depending on value:

switch(testEnumVar.Name)
{
    case nameof(TestEnum.One):
        ...
        break;
    case nameof(TestEnum.Two):
        ...
        break;
    case nameof(TestEnum.Three):
        ...
        break;
    default:
        ...
        break;
}

Using pattern matching:

switch(testEnumVar)
{
    case null:
        ...
        break;
    case var e when e.Equals(TestEnum.One):
        ...
        break;
    case var e when e.Equals(TestEnum.Two):
        ...
        break;
    case var e when e.Equals(TestEnum.Three):
        ...
        break;
    default:
        ...
        break;
}

Because of the limitations of pattern matching SmartEnum also provides a fluent interface to help create clean code:

testEnumVar
    .When(TestEnum.One).Then(() => ... )
    .When(TestEnum.Two).Then(() => ... )
    .When(TestEnum.Three).Then(() => ... )
    .Default( ... );

N.B. For performance critical code the fluent interface carries some overhead that you may wish to avoid. See the available benchmarks code for your use case.

SmartFlagEnum

Support has been added for a Flag functionality. This feature is similar to the behaviour seen when applying the [Flag] attribute to Enums in the .NET Framework All methods available on the SmartFlagEnum class return an IEnumerable<SmartFlagEnum> with one or more values depending on the value provided/method called. Some Functionality is shared with the original SmartEnum class, listed below are the variations.

Setting SmartFlagEnum Values

When setting the values for a SmartFlagEnum It is imperative to provide values as powers of two. If at least one value is not set as power of two or two or more power of two values are provided inconsecutively (eg: 1, 2, no four!, 8) a SmartFlagEnumDoesNotContainPowerOfTwoValuesException will be thrown.

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 Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);
        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);
        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

This behaviour can be disabled by applying the AllowUnsafeFlagEnumValuesAttribute to the smart enum class. Note: If power of two values are not provided the SmarFlagEnum will not behave as expected!

[AllowUnsafeFlagEnumValues]
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 Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);
        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);
        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

Combination values can be provided explicitly and will be returned in place of the multiple flag values that would have been returned from the FromValue() method.

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); -- Explicit `Combination` value
        public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);
        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);
        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

These explicit values can be provided above the highest allowable flag value without consequence, however attempting to access a value that is higher than the maximum flag value that has not explicitly been provided (for example 4) will cause a SmartEnumNotFoundException to be thrown.

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 AfterPay = new SmartFlagTestEnum(nameof(AfterPay), 5);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

    var myFlagEnums = FromValue(3) -- Works!
    -and-
    var myFlagEnums = FromValue(5) -- Works!
    -but-
    Var myFlagEnums = FromValue(4) -- will throw an exception :(

A Negative One (-1) value may be provided as an All value. When a value of -1 is passed into any of the FromValue() methods an IEnumerable containing all values (excluding 0) will be returned. If an explicit Combination value exists with a value of -1 this will be returned instead.

public class SmartFlagTestEnum : SmartFlagEnum<SmartFlagTestEnum>
    {
        public static readonly SmartFlagTestEnum All = new SmartFlagTestEnum(nameof(All), -1);
        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 Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);
        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);
        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);

        public SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

Usage - (SmartFlagEnum)

public abstract class EmployeeType : SmartFlagEnum<EmployeeType>
    {
        public static readonly EmployeeType Director = new DirectorType();
        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 DirectorType : EmployeeType
        {
            public DirectorType() : base("Director", 1) { }

            public override decimal BonusSize => 100_000m;
        }

        private sealed class ManagerType : EmployeeType
        {
            public ManagerType() : base("Manager", 2) { }

            public override decimal BonusSize => 10_000m;
        }

        private sealed class AssistantType : EmployeeType
        {
            public AssistantType() : base("Assistant", 4) { }

            public override decimal BonusSize => 1_000m;
        }
    }

    public class SmartFlagEnumUsageExample
    {
        public void UseSmartFlagEnumOne()
        {
            var result = EmployeeType.FromValue(3).ToList();

            var outputString = "";
            foreach (var employeeType in result)
            {
                outputString += $"{employeeType.Name} earns ${employeeType.BonusSize} bonus this year.\n";
            }

                => "Director earns $100000 bonus this year.\n"
                   "Manager earns $10000 bonus this year.\n"
        }

        public void UseSmartFlagEnumTwo()
        {
            EmployeeType.FromValueToString(-1)
                => "Director, Manager, Assistant"
        }

        public void UseSmartFlagEnumTwo()
        {
            EmployeeType.FromValueToString(EmployeeType.Assistant | EmployeeType.Director)
                => "Director, Assistant"
        }
    }

FromName()

Access an IEnumerable of enum instances by matching a string containing one or more enum names seperated by commas to its Names property:

var myFlagEnums = TestFlagEnum.FromName("One, Two");

Exception SmartEnumNotFoundException is thrown when no names are found. Alternatively, you can use TryFromName that returns false when no names are found:

if (TestFlagEnum.TryFromName("One, Two", out var myFlagEnums))
{
    // use myFlagEnums here
}

Both methods have a ignoreCase parameter (the default is case sensitive).

FromValue()

Access an IEnumerable of enum instances by matching a value:

var myFlagEnums = TestFlagEnum.FromValue(3);

Exception SmartEnumNotFoundException is thrown when no values are found. Alternatively, you can use TryFromValue that returns false when values are not found:

if (TestFlagEnum.TryFromValue(3, out var myFlagEnums))
{
    // use myFlagEnums here
}

Note: Negative values other than (-1) passed into this method will cause a NegativeValueArgumentException to be thrown, this behaviour can be disabled by applying the AllowNegativeInput attribute to the desired SmartFlagEnum class.

[AllowNegativeInput]
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 SmartFlagTestEnum(string name, int value) : base(name, value)
        {
        }
    }

Note: FromValue() will accept any input that can be succesfully parsed as an integer. If an invalid value is supplied it will throw an InvalidFlagEnumValueParseException.

FromValueToString()

Return a string representation of a series of enum instances name's:

var myFlagEnumString = TestFlagEnum.FromValueToString(3);

Exception SmartEnumNotFoundException is thrown when no values are found. Alternatively, you can use TryFromValueToString that returns false when values are not found:

if (TestFlagEnum.TryFromValueToString(3, out var myFlagEnumsAsString))
{
    // use myFlagEnumsAsString here
}

Note: Negative values other than (-1) passed into this method will cause a NegativeValueArgumentException to be thrown, this behaviour can be disabled by applying the AllowNegativeInput attribute to the desired SmartFlagEnum class.

BitWiseOrOperator

The FromValue() methods allow the Or ( | ) operator to be used to add enum values together and provide multiple values at once.

var myFlagEnums = TestFlagEnum.FromValue(TestFlagEnum.One | TestFlagEnum.Two);

This will only work where the type of the SmartFlagEnum has been specified as Int32 or else can be explicitly cast as an Int32.

var myFlagEnums = TestFlagEnumDecimal.FromValue((int)TestFlagEnum.One | (int)TestFlagEnum.Two);

Persisting with EF Core 2.1 or higher

EF Core 2.1 introduced value conversions which can be used to map SmartEnum types to simple database types. For example, given an entity named Policy with a property PolicyStatus that is a SmartEnum, you could use the following code to persist just the value to the database:

protected override void OnModelCreating(ModelBuilder builder)
{
    base.OnModelCreating(builder);

    builder.Entity<Policy>()
        .Property(p => p.PolicyStatus)
        .HasConversion(
            p => p.Value,
            p => PolicyStatus.FromValue(p));
}

Remember, you need to implement your own parameterless constructor to make it works with db context. See #103 issue.

Using SmartEnum.EFCore

EF Core 6 introduced pre-convention model configuration which allows value conversions to be configured for specific types within a model. If you have installed Ardalis.SmartEnum.EFCore it is sufficient to add the following line at the beginning of the ConfigureConventions method:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.ConfigureSmartEnum();

    ...
}

For previous versions of EF Core, the following line can be added at the end of the OnModelCreating method:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    ...

    modelBuilder.ConfigureSmartEnum();
}

AutoFixture support

New instance of a SmartEnum should not be created. Instead, references to the existing ones should always be used. AutoFixture by default doesn't know how to do this. The Ardalis.SmartEnum.AutoFixture package includes a specimen builder for SmartEnum. Simply add the customization to the IFixture builder:

var fixture = new Fixture()
    .Customize(new SmartEnumCustomization());

var smartEnum = fixture.Create<TestEnum>();

Json<span></span>.NET support

When serializing a SmartEnum to JSON, only one of the properties (Value or Name) should be used. Json.NET by default doesn't know how to do this. The Ardalis.SmartEnum.JsonNet package includes a couple of converters to achieve this. Simply use the attribute JsonConverterAttribute to assign one of the converters to the SmartEnum to be de/serialized:

public class TestClass
{
    [JsonConverter(typeof(SmartEnumNameConverter<TestEnum,int>))]
    public TestEnum Property { get; set; }
}

uses the Name:

{
  "Property": "One"
}

While this:

public class TestClass
{
    [JsonConverter(typeof(SmartEnumValueConverter<TestEnum,int>))]
    public TestEnum Property { get; set; }
}

uses the Value:

{
  "Property": 1
}

Note: The SmartFlagEnum works identically to the SmartEnum when being Serialized and Deserialized.

Dapper support

To enable Dapper support for SmartEnum values, add a SmartEnumTypeHandler to SqlMapper for the given SmartEnum type. There are two inheritors of SmartEnumTypeHandler: SmartEnumByNameTypeHandler, which maps the Name of a SmartEnum to a database column, and SmartEnumByValueTypeHandler, which maps the Value of a SmartEnum 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>());

DapperSmartEnum

To avoid needing to explicitly register a SmartEnum type with Dapper, it can be done automatically by inheriting from DapperSmartEnumByName or DapperSmartEnumByValue instead of from SmartEnum.

public class TestEnumByName : DapperSmartEnumByName<TestEnumByName>
{
    public static readonly TestEnumByName One = new TestEnumByName(1);
    public static readonly TestEnumByName Two = new TestEnumByName(2);
    public static readonly TestEnumByName Three = new TestEnumByName(3);

    protected TestEnumByName(int value, [CallerMemberName] string name = null) : base(name, value)
    {
    }
}
public class TestEnumByValue : DapperSmartEnumByValue<TestEnumByValue>
{
    public static readonly TestEnumByValue One = new TestEnumByValue(1);
    public static readonly TestEnumByValue Two = new TestEnumByValue(2);
    public static readonly TestEnumByValue Three = new TestEnumByValue(3);

    protected TestEnumByValue(int value, [CallerMemberName] string name = null) : base(name, value)
    {
    }
}

Inheritors of DapperSmartEnum can be decorated with custom attributes in order to configure its type handler. Use DbTypeAttribute (e.g. [DbType(DbType.String)]) to specify that parameters should have their DbType property set to the specified value. Use DoNotSetDbTypeAttribute (e.g. [DoNotSetDbType]) to specify that parameters should not have their DbType property set. Use IgnoreCaseAttribute (e.g. [IgnoreCase]) when inheriting from DapperSmartEnumByName to specify that database values do not need to match the case of a SmartEnum Name.

Case Insensitive String Enum

When creating enums of strings, the default behaviour of SmartEnum is to compare the strings with a case sensitive comparer. It is possible to specify a different equality comparer for the enum values, for example a case insensitive one:

[SmartEnumStringComparer(StringComparison.InvariantCultureIgnoreCase)]
public class CaseInsensitiveEnum : SmartEnum<CaseInsensitiveEnum, string>
{
    protected CaseInsensitiveEnum(string name, string value) : base(name, value) { }

    public static CaseInsensitiveEnum One = new CaseInsensitiveEnum("One", "one");
    public static CaseInsensitiveEnum Two = new CaseInsensitiveEnum("Two", "two");
}

var e1 = CaseInsensitiveEnum.FromValue("ONE");
var e2 = CaseInsensitiveEnum.FromValue("one");

//e1 is equal to e2
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.2.0 91 4/19/2024