{"id":13595235,"url":"https://github.com/ardalis/SmartEnum","last_synced_at":"2025-04-09T10:33:14.338Z","repository":{"id":37549286,"uuid":"112747661","full_name":"ardalis/SmartEnum","owner":"ardalis","description":"A base class for quickly and easily creating strongly typed enum replacements in C#.","archived":false,"fork":false,"pushed_at":"2024-10-18T05:25:25.000Z","size":666,"stargazers_count":2186,"open_issues_count":80,"forks_count":170,"subscribers_count":23,"default_branch":"main","last_synced_at":"2024-10-29T15:10:31.367Z","etag":null,"topics":["clean","csharp","ddd","design-patterns","domain-driven-design","dotnet","dotnet-core","enum","hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ardalis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ardalis"}},"created_at":"2017-12-01T14:15:24.000Z","updated_at":"2024-10-28T12:19:47.000Z","dependencies_parsed_at":"2024-02-28T05:28:30.977Z","dependency_job_id":"207df458-df39-4eb4-9b48-e0dcedb851e3","html_url":"https://github.com/ardalis/SmartEnum","commit_stats":{"total_commits":284,"total_committers":37,"mean_commits":7.675675675675675,"dds":0.3943661971830986,"last_synced_commit":"3178f13160a39f50e94c92220df0ff7b64cf7553"},"previous_names":[],"tags_count":36,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ardalis%2FSmartEnum","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ardalis%2FSmartEnum/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ardalis%2FSmartEnum/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ardalis%2FSmartEnum/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ardalis","download_url":"https://codeload.github.com/ardalis/SmartEnum/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248020593,"owners_count":21034459,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clean","csharp","ddd","design-patterns","domain-driven-design","dotnet","dotnet-core","enum","hacktoberfest"],"created_at":"2024-08-01T16:01:46.148Z","updated_at":"2025-04-09T10:33:09.330Z","avatar_url":"https://github.com/ardalis.png","language":"C#","funding_links":["https://github.com/sponsors/ardalis"],"categories":["C#","C\\#","csharp","hacktoberfest","Architectural Patterns"],"sub_categories":["Exceptions \u0026 Validation"],"readme":"[![NuGet](https://img.shields.io/nuget/v/Ardalis.SmartEnum.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum)[![NuGet](https://img.shields.io/nuget/dt/Ardalis.SmartEnum.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum)\n![Last Publish Ardalis.SmartEnum to NuGet](https://github.com/ardalis/SmartEnum/workflows/publish%20Ardalis.SmartEnum%20to%20nuget/badge.svg)\n\n## Table Of Contents\n\n- [Table Of Contents](#table-of-contents)\n  * [Sub-packages](#sub-packages)\n  * [Give a Star! ⭐](give-a-star-star)\n- [SmartEnum](#smart-enum)\n  * [Contributors](#contributors)\n- [Install](#install)\n  * [Version](#version)\n- [Usage](#usage)\n  * [List](#list)\n  * [FromName()](#fromname)\n  * [FromValue()](#fromvalue)\n  * [ToString()](#tostring)\n  * [Switch](#switch)\n  * [SmartFlagEnum](#smartflagenum)\n  * [Setting SmartFlagEnum Values](#setting-smartflagenum-values)\n  * [Usage - (SmartFlagEnum)](#usage---smartflagenum)\n  * [FromName()](#fromname-1)\n  * [FromValue()](#fromvalue-1)\n  * [FromValueToString()](#fromvaluetostring)\n  * [BitWiseOrOperator](#bitwiseoroperator)\n  * [Persisting with EF Core 2.1 or higher](#persisting-with-ef-core-21-or-higher)\n  * [Using SmartEnum.EFCore](#using-smartenumefcore)\n  * [AutoFixture support](#autofixture-support)\n  * [Json support](#jsonnet-support)\n  * [Dapper support](#dapper-support)\n  * [DapperSmartEnum](#dappersmartenum)\n  * [Case Insensitive String Enum](#case-insensitive-string-enum)\n  * [Name Validation Attribute](#name-validation-attribute)\n  * [Examples in the Real World](#examples-in-the-real-world)\n  * [References](#references)\n\n### Sub-packages\n\nSmartEnum.AutoFixture: [![NuGet](https://img.shields.io/nuget/v/Ardalis.SmartEnum.AutoFixture.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.AutoFixture)[![NuGet](https://img.shields.io/nuget/dt/Ardalis.SmartEnum.AutoFixture.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.AutoFixture)![publish SmartEnum.AutoFixture to nuget](https://github.com/ardalis/SmartEnum/workflows/publish%20SmartEnum.AutoFixture%20to%20nuget/badge.svg)\n\nSmartEnum.Dapper: [![NuGet](https://img.shields.io/nuget/v/Ardalis.SmartEnum.Dapper.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.Dapper)[![NuGet](https://img.shields.io/nuget/dt/Ardalis.SmartEnum.Dapper.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.Dapper)![publish SmartEnum.Dapper to nuget](https://github.com/ardalis/SmartEnum/workflows/publish%20SmartEnum.Dapper%20to%20nuget/badge.svg)\n\nSmartEnum.EFCore: [![NuGet](https://img.shields.io/nuget/v/Ardalis.SmartEnum.EFCore.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.EFCore)[![NuGet](https://img.shields.io/nuget/dt/Ardalis.SmartEnum.EFCore.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.EFCore)![publish SmartEnum.EFCore to nuget](https://github.com/ardalis/SmartEnum/workflows/publish%20SmartEnum.EFCore%20to%20nuget/badge.svg)\n\nSmartEnum.JsonNet: [![NuGet](https://img.shields.io/nuget/v/Ardalis.SmartEnum.JsonNet.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.JsonNet)[![NuGet](https://img.shields.io/nuget/dt/Ardalis.SmartEnum.JsonNet.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.JsonNet)![publish jsonnet to nuget](https://github.com/ardalis/SmartEnum/workflows/publish%20SmartEnum.JsonNet%20to%20nuget/badge.svg)\n\nSmartEnum.MessagePack: [![NuGet](https://img.shields.io/nuget/v/Ardalis.SmartEnum.MessagePack.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.MessagePack)[![NuGet](https://img.shields.io/nuget/dt/Ardalis.SmartEnum.MessagePack.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.MessagePack)![publish SmartEnum.MessagePack to nuget](https://github.com/ardalis/SmartEnum/workflows/publish%20SmartEnum.MessagePack%20to%20nuget/badge.svg)\n\nSmartEnum.ProtoBufNet: [![NuGet](https://img.shields.io/nuget/v/Ardalis.SmartEnum.ProtoBufNet.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.ProtoBufNet)[![NuGet](https://img.shields.io/nuget/dt/Ardalis.SmartEnum.ProtoBufNet.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.ProtoBufNet)![publish SmartEnum.ProtoBufNet to nuget](https://github.com/ardalis/SmartEnum/workflows/publish%20SmartEnum.ProtoBufNet%20to%20nuget/badge.svg)\n\nSmartEnum.SystemTextJson: [![NuGet](https://img.shields.io/nuget/v/Ardalis.SmartEnum.SystemTextJson.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.SystemTextJson)[![NuGet](https://img.shields.io/nuget/dt/Ardalis.SmartEnum.SystemTextJson.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.SystemTextJson)![publish SmartEnum.SystemTextJson to nuget](https://github.com/ardalis/SmartEnum/workflows/publish%20SmartEnum.SystemTextJson%20to%20nuget/badge.svg)\n\nSmartEnum.Utf8Json: [![NuGet](https://img.shields.io/nuget/v/Ardalis.SmartEnum.Utf8Json.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.Utf8Json)[![NuGet](https://img.shields.io/nuget/dt/Ardalis.SmartEnum.Utf8Json.svg)](https://www.nuget.org/packages/Ardalis.SmartEnum.Utf8Json)![publish SmartEnum.Utf8Json to nuget](https://github.com/ardalis/SmartEnum/workflows/publish%20SmartEnum.Utf8Json%20to%20nuget/badge.svg)\n\n## Give a Star! :star:\n\nIf you like or are using this project please give it a star. Thanks!\n\n# Smart Enum\n\nAn implementation of a [type-safe object-oriented alternative](https://codeblog.jonskeet.uk/2006/01/05/classenum/) to [C# enum](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum).\n\n## Contributors\n\nThanks to [Scott DePouw](https://github.com/sdepouw), [Antão Almada](https://github.com/aalmada), and [Nagasudhir Pulla](https://github.com/nagasudhirpulla) for help with this project!\n\n# Install\n\nThe framework is provided as a set of NuGet packages. In many cases you'll only need the base package, but if you need serialization and/or ORM support there are many implementation-specific packages available to assist.\n\nTo install the minimum requirements:\n\n```\nInstall-Package Ardalis.SmartEnum\n```\n\nTo install support for serialization, AutoFixture, EF Core, Model Binding, or Dapper select the lines that apply:\n\n```\nInstall-Package Ardalis.SmartEnum.AutoFixture\nInstall-Package Ardalis.SmartEnum.JsonNet\nInstall-Package Ardalis.SmartEnum.SystemTextJson\nInstall-Package Ardalis.SmartEnum.Utf8Json\nInstall-Package Ardalis.SmartEnum.MessagePack\nInstall-Package Ardalis.SmartEnum.ProtoBufNet\nInstall-Package Ardalis.SmartEnum.EFCore\nInstall-Package Ardalis.SmartEnum.ModelBinding\nInstall-Package Ardalis.SmartEnum.Dapper\n```\n\n## Version\n\nThe latest version of the package supports .NET 8 and NetStandard 2.0.\n\n## Usage\n\nDefine your smart enum by inheriting from `SmartEnum\u003cTEnum\u003e` where `TEnum` is the type you're declaring. For [example](/test/SmartEnum.UnitTests/TestEnum.cs):\n\n```csharp\nusing Ardalis.SmartEnum;\n\npublic sealed class TestEnum : SmartEnum\u003cTestEnum\u003e\n{\n    public static readonly TestEnum One = new TestEnum(nameof(One), 1);\n    public static readonly TestEnum Two = new TestEnum(nameof(Two), 2);\n    public static readonly TestEnum Three = new TestEnum(nameof(Three), 3);\n\n    private TestEnum(string name, int value) : base(name, value)\n    {\n    }\n}\n```\n\nThe default value type is `int` but it can be set using the second generic argument `TValue`.\nThe string alias can also be set explicitly, where spaces are allowed.\n\n```csharp\nusing Ardalis.SmartEnum;\n\npublic sealed class TestEnum : SmartEnum\u003cTestEnum, ushort\u003e\n{\n    public static readonly TestEnum One = new TestEnum(\"A string!\", 1);\n    public static readonly TestEnum Two = new TestEnum(\"Another string!\", 2);\n    public static readonly TestEnum Three = new TestEnum(\"Yet another string!\", 3);\n\n    private TestEnum(string name, ushort value) : base(name, value)\n    {\n    }\n}\n```\n\nJust like regular `enum`, more than one string can be assigned to the same value but only one value can be assigned to a string:\n\n```csharp\nusing Ardalis.SmartEnum;\n\npublic sealed class TestEnum : SmartEnum\u003cTestEnum\u003e\n{\n    public static readonly TestEnum One = new TestEnum(nameof(One), 1);\n    public static readonly TestEnum Two = new TestEnum(nameof(Two), 2);\n    public static readonly TestEnum Three = new TestEnum(nameof(Three), 3);\n    public static readonly TestEnum AnotherThree = new TestEnum(nameof(AnotherThree), 3);\n    // public static TestEnum Three = new TestEnum(nameof(Three), 4); -\u003e throws exception\n\n    private TestEnum(string name, int value) : base(name, value)\n    {\n    }\n}\n```\n\nIn this case, `TestEnum.FromValue(3)` will return the first instance found, either `TestEnum.Three` or `TestEnum.AnotherThree`. No order should be assumed.\n\nThe `Value` content is used when comparing two smart enums, while `Name` is ignored:\n\n```csharp\nTestEnum.One.Equals(TestEnum.One); // returns true\nTestEnum.One.Equals(TestEnum.Three); // returns false\nTestEnum.Three.Equals(TestEnum.AnotherThree); // returns true\n```\n\nInheritance can be used to add \"behavior\" to a smart enum.\n\nThis example adds a `BonusSize` property, avoiding the use of the `switch` typically used with regular enums:\n\n```csharp\nusing Ardalis.SmartEnum;\n\npublic abstract class EmployeeType : SmartEnum\u003cEmployeeType\u003e\n{\n    public static readonly EmployeeType Manager = new ManagerType();\n    public static readonly EmployeeType Assistant = new AssistantType();\n\n    private EmployeeType(string name, int value) : base(name, value)\n    {\n    }\n\n    public abstract decimal BonusSize { get; }\n\n    private sealed class ManagerType : EmployeeType\n    {\n        public ManagerType() : base(\"Manager\", 1) {}\n\n        public override decimal BonusSize =\u003e 10_000m;\n    }\n\n    private sealed class AssistantType : EmployeeType\n    {\n        public AssistantType() : base(\"Assistant\", 2) {}\n\n        public override decimal BonusSize =\u003e 1_000m;\n    }\n}\n```\n\nYou can take this a step further and use the `ManagerType` and associated `BonusSize` property in a parent class like so:\n\n```csharp\npublic class Manager\n{\n    private ManagerType _managerType { get; set; }\n    public string Type\n    {\n        get =\u003e _managerType.Name;\n        set\n        {\n            if (!ManagerType.TryFromName(value, true, out var parsed))\n            {\n                throw new Exception($\"Invalid manager type of '{value}'\");\n            }\n            _managerType = parsed;\n        }\n    }\n\n    public string BonusSize\n    {\n        get =\u003e _managerType.BonusSize();\n        set =\u003e _bonusSize_ = value;\n    }\n}\n```\n\nThis 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`.\n\n```csharp\nusing Ardalis.SmartEnum;\n\npublic abstract class ReservationStatus : SmartEnum\u003cReservationStatus\u003e\n{\n    public static readonly ReservationStatus New = new NewStatus();\n    public static readonly ReservationStatus Accepted = new AcceptedStatus();\n    public static readonly ReservationStatus Paid = new PaidStatus();\n    public static readonly ReservationStatus Cancelled = new CancelledStatus();\n\n    private ReservationStatus(string name, int value) : base(name, value)\n    {\n    }\n\n    public abstract bool CanTransitionTo(ReservationStatus next);\n\n    private sealed class NewStatus: ReservationStatus\n    {\n        public NewStatus() : base(\"New\", 0)\n        {\n        }\n\n        public override bool CanTransitionTo(ReservationStatus next) =\u003e\n            next == ReservationStatus.Accepted || next == ReservationStatus.Cancelled;\n    }\n\n    private sealed class AcceptedStatus: ReservationStatus\n    {\n        public AcceptedStatus() : base(\"Accepted\", 1)\n        {\n        }\n\n        public override bool CanTransitionTo(ReservationStatus next) =\u003e\n            next == ReservationStatus.Paid || next == ReservationStatus.Cancelled;\n    }\n\n    private sealed class PaidStatus: ReservationStatus\n    {\n        public PaidStatus() : base(\"Paid\", 2)\n        {\n        }\n\n        public override bool CanTransitionTo(ReservationStatus next) =\u003e\n            next == ReservationStatus.Cancelled;\n    }\n\n    private sealed class CancelledStatus: ReservationStatus\n    {\n        public CancelledStatus() : base(\"Cancelled\", 3)\n        {\n        }\n\n        public override bool CanTransitionTo(ReservationStatus next) =\u003e\n            false;\n    }\n}\n```\n\n### List\n\nYou can list all of the available options using the enum's static `List` property:\n\n```csharp\nforeach (var option in TestEnum.List)\n    Console.WriteLine(option.Name);\n```\n\n`List` returns an `IReadOnlyCollection` so you can use the `Count` property to efficiently get the number of available options.\n\n```csharp\nvar count = TestEnum.List.Count;\n```\n\n### FromName()\n\nAccess an instance of an enum by matching a string to its `Name` property:\n\n```csharp\nvar myEnum = TestEnum.FromName(\"One\");\n```\n\nException `SmartEnumNotFoundException` is thrown when name is not found. Alternatively, you can use `TryFromName` that returns `false` when name is not found:\n\n```csharp\nif (TestEnum.TryFromName(\"One\", out var myEnum))\n{\n    // use myEnum here\n}\n```\n\nBoth methods have a `ignoreCase` parameter (the default is case sensitive).\n\n### FromValue()\n\nAccess an instance of an enum by matching its value:\n\n```csharp\nvar myEnum = TestEnum.FromValue(1);\n```\n\nException `SmartEnumNotFoundException` is thrown when value is not found. Alternatively, you can use `TryFromValue` that returns `false` when value is not found:\n\n```csharp\nif (TestEnum.TryFromValue(1, out var myEnum))\n{\n    // use myEnum here\n}\n```\n\n### ToString()\n\nDisplay an enum using the `ToString()` override:\n\n```csharp\nConsole.WriteLine(TestEnum.One); // One\n```\n\n### Switch\n\nGiven an instance of a TestEnum, switch depending on value:\n\n```csharp\nswitch(testEnumVar.Name)\n{\n    case nameof(TestEnum.One):\n        ...\n        break;\n    case nameof(TestEnum.Two):\n        ...\n        break;\n    case nameof(TestEnum.Three):\n        ...\n        break;\n    default:\n        ...\n        break;\n}\n```\n\nUsing pattern matching:\n\n```csharp\nswitch(testEnumVar)\n{\n    case null:\n        ...\n        break;\n    case var e when e.Equals(TestEnum.One):\n        ...\n        break;\n    case var e when e.Equals(TestEnum.Two):\n        ...\n        break;\n    case var e when e.Equals(TestEnum.Three):\n        ...\n        break;\n    default:\n        ...\n        break;\n}\n```\nBecause of the limitations of pattern matching SmartEnum also provides a fluent interface to help create clean code:\n\n```csharp\ntestEnumVar\n    .When(TestEnum.One).Then(() =\u003e ... )\n    .When(TestEnum.Two).Then(() =\u003e ... )\n    .When(TestEnum.Three).Then(() =\u003e ... )\n    .Default( ... );\n```\n\nN.B. For performance critical code the fluent interface carries some overhead that you may wish to avoid. See the available [benchmarks](benchmarks/SmartEnum.Benchmarks) code for your use case.\n\n### SmartFlagEnum\n\nSupport has been added for a `Flag` functionality.\nThis feature is similar to the behaviour seen when applying the `[Flag]` attribute to Enums in the .NET Framework\nAll methods available on the `SmartFlagEnum` class return an `IEnumerable\u003cSmartFlagEnum\u003e` with one or more values depending on the value provided/method called.\nSome Functionality is shared with the original SmartEnum class, listed below are the variations.\n\n### Setting SmartFlagEnum Values\n\nWhen 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.\n\n```csharp\npublic class SmartFlagTestEnum : SmartFlagEnum\u003cSmartFlagTestEnum\u003e\n    {\n        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);\n        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);\n        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);\n        public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);\n        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);\n        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);\n\n        public SmartFlagTestEnum(string name, int value) : base(name, value)\n        {\n        }\n    }\n```\n\nThis 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!\n\n```csharp\n[AllowUnsafeFlagEnumValues]\npublic class SmartFlagTestEnum : SmartFlagEnum\u003cSmartFlagTestEnum\u003e\n    {\n        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);\n        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);\n        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);\n        public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);\n        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);\n        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);\n\n        public SmartFlagTestEnum(string name, int value) : base(name, value)\n        {\n        }\n    }\n```\n\n`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.\n\n```csharp\npublic class SmartFlagTestEnum : SmartFlagEnum\u003cSmartFlagTestEnum\u003e\n    {\n        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);\n        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);\n        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);\n        public static readonly SmartFlagTestEnum CardAndCash = new SmartFlagTestEnum(nameof(CardAndCash), 3); -- Explicit `Combination` value\n        public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);\n        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);\n        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);\n\n        public SmartFlagTestEnum(string name, int value) : base(name, value)\n        {\n        }\n    }\n```\n\nThese 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.\n\n```csharp\npublic class SmartFlagTestEnum : SmartFlagEnum\u003cSmartFlagTestEnum\u003e\n    {\n        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);\n        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);\n        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);\n        public static readonly SmartFlagTestEnum AfterPay = new SmartFlagTestEnum(nameof(AfterPay), 5);\n\n        public SmartFlagTestEnum(string name, int value) : base(name, value)\n        {\n        }\n    }\n\n    var myFlagEnums = FromValue(3) -- Works!\n    -and-\n    var myFlagEnums = FromValue(5) -- Works!\n    -but-\n    Var myFlagEnums = FromValue(4) -- will throw an exception :(\n```\n\nA 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.\nIf an explicit `Combination` value exists with a value of -1 this will be returned instead.\n\n```csharp\npublic class SmartFlagTestEnum : SmartFlagEnum\u003cSmartFlagTestEnum\u003e\n    {\n        public static readonly SmartFlagTestEnum All = new SmartFlagTestEnum(nameof(All), -1);\n        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);\n        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);\n        public static readonly SmartFlagTestEnum Cash = new SmartFlagTestEnum(nameof(Cash), 2);\n        public static readonly SmartFlagTestEnum Bpay = new SmartFlagTestEnum(nameof(Bpay), 4);\n        public static readonly SmartFlagTestEnum Paypal = new SmartFlagTestEnum(nameof(Paypal), 8);\n        public static readonly SmartFlagTestEnum BankTransfer = new SmartFlagTestEnum(nameof(BankTransfer), 16);\n\n        public SmartFlagTestEnum(string name, int value) : base(name, value)\n        {\n        }\n    }\n```\n\n### Usage - (SmartFlagEnum)\n\n```csharp\npublic abstract class EmployeeType : SmartFlagEnum\u003cEmployeeType\u003e\n    {\n        public static readonly EmployeeType Director = new DirectorType();\n        public static readonly EmployeeType Manager = new ManagerType();\n        public static readonly EmployeeType Assistant = new AssistantType();\n\n        private EmployeeType(string name, int value) : base(name, value)\n        {\n        }\n\n        public abstract decimal BonusSize { get; }\n\n        private sealed class DirectorType : EmployeeType\n        {\n            public DirectorType() : base(\"Director\", 1) { }\n\n            public override decimal BonusSize =\u003e 100_000m;\n        }\n\n        private sealed class ManagerType : EmployeeType\n        {\n            public ManagerType() : base(\"Manager\", 2) { }\n\n            public override decimal BonusSize =\u003e 10_000m;\n        }\n\n        private sealed class AssistantType : EmployeeType\n        {\n            public AssistantType() : base(\"Assistant\", 4) { }\n\n            public override decimal BonusSize =\u003e 1_000m;\n        }\n    }\n\n    public class SmartFlagEnumUsageExample\n    {\n        public void UseSmartFlagEnumOne()\n        {\n            var result = EmployeeType.FromValue(3).ToList();\n\n            var outputString = \"\";\n            foreach (var employeeType in result)\n            {\n                outputString += $\"{employeeType.Name} earns ${employeeType.BonusSize} bonus this year.\\n\";\n            }\n\n                =\u003e \"Director earns $100000 bonus this year.\\n\"\n                   \"Manager earns $10000 bonus this year.\\n\"\n        }\n\n        public void UseSmartFlagEnumTwo()\n        {\n            EmployeeType.FromValueToString(-1)\n                =\u003e \"Director, Manager, Assistant\"\n        }\n\n        public void UseSmartFlagEnumTwo()\n        {\n            EmployeeType.FromValueToString(EmployeeType.Assistant | EmployeeType.Director)\n                =\u003e \"Director, Assistant\"\n        }\n    }\n\n```\n\n### FromName()\n\nAccess an `IEnumerable` of enum instances by matching a string containing one or more enum names seperated by commas to its `Names` property:\n\n```csharp\nvar myFlagEnums = TestFlagEnum.FromName(\"One, Two\");\n```\n\nException `SmartEnumNotFoundException` is thrown when no names are found. Alternatively, you can use `TryFromName` that returns `false` when no names are found:\n\n```csharp\nif (TestFlagEnum.TryFromName(\"One, Two\", out var myFlagEnums))\n{\n    // use myFlagEnums here\n}\n```\n\nBoth methods have a `ignoreCase` parameter (the default is case sensitive).\n\n### FromValue()\n\nAccess an `IEnumerable` of enum instances by matching a value:\n\n```csharp\nvar myFlagEnums = TestFlagEnum.FromValue(3);\n```\n\nException `SmartEnumNotFoundException` is thrown when no values are found. Alternatively, you can use `TryFromValue` that returns `false` when values are not found:\n\n```csharp\nif (TestFlagEnum.TryFromValue(3, out var myFlagEnums))\n{\n    // use myFlagEnums here\n}\n```\n\nNote: 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.\n\n```csharp\n[AllowNegativeInput]\npublic class SmartFlagTestEnum : SmartFlagEnum\u003cSmartFlagTestEnum\u003e\n    {\n        public static readonly SmartFlagTestEnum None = new SmartFlagTestEnum(nameof(None), 0);\n        public static readonly SmartFlagTestEnum Card = new SmartFlagTestEnum(nameof(Card), 1);\n\n        public SmartFlagTestEnum(string name, int value) : base(name, value)\n        {\n        }\n    }\n```\n\nNote: `FromValue()` will accept any input that can be succesfully parsed as an integer.  If an invalid value is supplied it will throw an `InvalidFlagEnumValueParseException`.\n\n### FromValueToString()\n\nReturn a string representation of a series of enum instances name's:\n\n```csharp\nvar myFlagEnumString = TestFlagEnum.FromValueToString(3);\n```\n\nException `SmartEnumNotFoundException` is thrown when no values are found. Alternatively, you can use `TryFromValueToString` that returns `false` when values are not found:\n\n```csharp\nif (TestFlagEnum.TryFromValueToString(3, out var myFlagEnumsAsString))\n{\n    // use myFlagEnumsAsString here\n}\n```\n\nNote: 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.\n\n### BitWiseOrOperator\n\nThe `FromValue()` methods allow the Or ( | ) operator to be used to `add` enum values together and provide multiple values at once.\n\n```csharp\nvar myFlagEnums = TestFlagEnum.FromValue(TestFlagEnum.One | TestFlagEnum.Two);\n```\n\nThis will only work where the type of the `SmartFlagEnum` has been specified as `Int32` or else can be explicitly cast as an `Int32`.\n\n```csharp\nvar myFlagEnums = TestFlagEnumDecimal.FromValue((int)TestFlagEnum.One | (int)TestFlagEnum.Two);\n```\n\n### Persisting with EF Core 2.1 or higher\n\nEF Core 2.1 introduced [value conversions](https://docs.microsoft.com/en-us/ef/core/modeling/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:\n\n```csharp\nprotected override void OnModelCreating(ModelBuilder builder)\n{\n    base.OnModelCreating(builder);\n\n    builder.Entity\u003cPolicy\u003e()\n        .Property(p =\u003e p.PolicyStatus)\n        .HasConversion(\n            p =\u003e p.Value,\n            p =\u003e PolicyStatus.FromValue(p));\n}\n```\n\nRemember, you need to implement your own parameterless constructor to make it works with db context. See [#103 issue](https://github.com/ardalis/SmartEnum/issues/103).\n\n#### Using SmartEnum.EFCore\n\nEF 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:\n\n```csharp\nprotected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)\n{\n    configurationBuilder.ConfigureSmartEnum();\n\n    ...\n}\n```\n\nFor previous versions of EF Core, the following line can be added at the end of the `OnModelCreating` method:\n\n```csharp\nprotected override void OnModelCreating(ModelBuilder modelBuilder)\n{\n    ...\n\n    modelBuilder.ConfigureSmartEnum();\n}\n```\n\n## AutoFixture support\n\nNew instance of a `SmartEnum` should not be created. Instead, references to the existing ones should always be used. [AutoFixture](https://github.com/AutoFixture/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:\n\n```csharp\nvar fixture = new Fixture()\n    .Customize(new SmartEnumCustomization());\n\nvar smartEnum = fixture.Create\u003cTestEnum\u003e();\n```\n\n## Json support\n\nWhen serializing a `SmartEnum` to JSON, only one of the properties (`Value` or `Name`) should be used. \n\n### Json\u003cspan\u003e\u003c/span\u003e.Net\n[Json.NET](https://www.newtonsoft.com/json) 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](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonConverter.htm) to assign one of the converters to the `SmartEnum` to be de/serialized:\n\n### System\u003cspan\u003e\u003c/span\u003e.Text\u003cspan\u003e\u003c/span\u003e.Json\n[System.Text.Json](https://learn.microsoft.com/en-us/dotnet/api/system.text.json?view=net-8.0) by default doesn't know how to do this. The `Ardalis.SmartEnum.SystemTextJson` package includes a couple of converters to achieve this. Simply use the attribute [JsonConverterAttribute](https://learn.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonconverterattribute?view=net-8.0) to assign one of the converters to the `SmartEnum` to be de/serialized:\n\n```csharp\npublic class TestClass\n{\n    [JsonConverter(typeof(SmartEnumNameConverter\u003cTestEnum,int\u003e))]\n    public TestEnum Property { get; set; }\n}\n```\n\nuses the `Name`:\n\n```json\n{\n  \"Property\": \"One\"\n}\n```\n\nWhile this:\n\n```csharp\npublic class TestClass\n{\n    [JsonConverter(typeof(SmartEnumValueConverter\u003cTestEnum,int\u003e))]\n    public TestEnum Property { get; set; }\n}\n```\n\nuses the `Value`:\n\n```json\n{\n  \"Property\": 1\n}\n```\n\nNote: The SmartFlagEnum works identically to the SmartEnum when being Serialized and Deserialized.\n\n## Dapper support\n\nTo enable Dapper support for `SmartEnum` values, add a `SmartEnumTypeHandler` to `SqlMapper` for the\ngiven `SmartEnum` type. There are two inheritors of `SmartEnumTypeHandler`:\n`SmartEnumByNameTypeHandler`, which maps the Name of a `SmartEnum` to a database column, and\n`SmartEnumByValueTypeHandler`, which maps the Value of a `SmartEnum` to a database column.\n\n```csharp\n// Maps the name of TestEnum objects (e.g. \"One\", \"Two\", or \"Three\") to a database column.\nSqlMapper.AddTypeHandler(typeof(TestEnum), new SmartEnumByNameTypeHandler\u003cTestEnum\u003e());\n```\n\n```csharp\n// Maps the value of TestEnum objects (e.g. 1, 2, or 3) to a database column.\nSqlMapper.AddTypeHandler(typeof(TestEnum), new SmartEnumByValueTypeHandler\u003cTestEnum\u003e());\n```\n\n### DapperSmartEnum\n\nTo avoid needing to explicitly register a `SmartEnum` type with Dapper, it can be done automatically\nby inheriting from `DapperSmartEnumByName` or `DapperSmartEnumByValue` instead of from `SmartEnum`.\n\n```csharp\npublic class TestEnumByName : DapperSmartEnumByName\u003cTestEnumByName\u003e\n{\n    public static readonly TestEnumByName One = new TestEnumByName(1);\n    public static readonly TestEnumByName Two = new TestEnumByName(2);\n    public static readonly TestEnumByName Three = new TestEnumByName(3);\n\n    protected TestEnumByName(int value, [CallerMemberName] string name = null) : base(name, value)\n    {\n    }\n}\n```\n\n```csharp\npublic class TestEnumByValue : DapperSmartEnumByValue\u003cTestEnumByValue\u003e\n{\n    public static readonly TestEnumByValue One = new TestEnumByValue(1);\n    public static readonly TestEnumByValue Two = new TestEnumByValue(2);\n    public static readonly TestEnumByValue Three = new TestEnumByValue(3);\n\n    protected TestEnumByValue(int value, [CallerMemberName] string name = null) : base(name, value)\n    {\n    }\n}\n```\n\nInheritors of `DapperSmartEnum` can be decorated with custom attributes in order to configure\nits type handler. Use `DbTypeAttribute` (e.g. `[DbType(DbType.String)]`) to specify that parameters\nshould have their `DbType` property set to the specified value. Use `DoNotSetDbTypeAttribute` (e.g.\n`[DoNotSetDbType]`) to specify that parameters should not have their `DbType` property set. Use\n`IgnoreCaseAttribute` (e.g. `[IgnoreCase]`) when inheriting from `DapperSmartEnumByName` to specify\nthat database values do not need to match the case of a SmartEnum Name.\n\n### Case Insensitive String Enum\n\nWhen creating enums of strings, the default behaviour of SmartEnum is to compare the strings with a case sensitive comparer.\nIt is possible to specify a different equality comparer for the enum values, for example a case insensitive one:\n\n```csharp\n[SmartEnumStringComparer(StringComparison.InvariantCultureIgnoreCase)]\npublic class CaseInsensitiveEnum : SmartEnum\u003cCaseInsensitiveEnum, string\u003e\n{\n    protected CaseInsensitiveEnum(string name, string value) : base(name, value) { }\n\n    public static CaseInsensitiveEnum One = new CaseInsensitiveEnum(\"One\", \"one\");\n    public static CaseInsensitiveEnum Two = new CaseInsensitiveEnum(\"Two\", \"two\");\n}\n\nvar e1 = CaseInsensitiveEnum.FromValue(\"ONE\");\nvar e2 = CaseInsensitiveEnum.FromValue(\"one\");\n\n//e1 is equal to e2\n```\n## Name Validation Attribute\nThe DataAnnotations ValidationAttribute `SmartEnumNameAttribute` allows you to validate your models, mandating that when provided a value it must be matching the name of a given `SmartEnum`. This attribute allows `null` values (use `[Required]` to disallow nulls).\n\nIn addition to specifying the `SmartEnum` to match, you may also pass additional parameters:\n- `allowCaseInsensitiveMatch` (default `false`)\n- `errorMessage` (default `\"{0} must be one of: {1}\"`): A format string to customize the error\n  - `{0}` is the name of the property being validated\n  - `{1}` is the comma-separated list of valid `SmartEnum` names\n\n### Example of Name Validation Attribute\n```csharp\npublic sealed class ExampleSmartEnum : SmartEnum\u003cExampleSmartEnum\u003e\n{\n    public static readonly ExampleSmartEnum Foo = new ExampleSmartEnum(nameof(Foo), 1);\n    public static readonly ExampleSmartEnum Bar = new ExampleSmartEnum(nameof(Bar), 2);\n    \n    private ExampleSmartEnum(string name, int value) : base(name, value) { }\n}\n\npublic class ExampleModel\n{\n    [Required]\n    [SmartEnumName(typeof(ExampleSmartEnum)]\n    public string MyExample { get; set; } // must be \"Foo\" or \"Bar\"\n    \n    [SmartEnumName(typeof(ExampleSmartEnum), allowCaseInsensitiveMatch: true)]\n    public string CaseInsensitiveExample { get; set; } // \"Foo\", \"foo\", etc. allowed; null also allowed here\n}\n```\n\n## Examples in the Real World\n\n- [Race](https://github.com/pdevito3/PeakLimsApi/blob/main/PeakLims/src/PeakLims/Domain/Races/Race.cs)\n\n[Search for more](https://github.com/search?l=C%23\u0026q=Ardalis.SmartEnum\u0026type=Code)\n\n## References\n\n- [Listing Strongly Typed Enums...)](https://ardalis.com/listing-strongly-typed-enum-options-in-c)\n- [Enum Alternatives in C#](https://ardalis.com/enum-alternatives-in-c)\n- [Smarter Enumerations (podcast episode)](http://www.weeklydevtips.com/014)\n- [Persisting a Smart Enum with Entity Framework Core](https://blog.nimblepros.com/blogs/persisting-a-smart-enum-with-entity-framework-core/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fardalis%2FSmartEnum","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fardalis%2FSmartEnum","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fardalis%2FSmartEnum/lists"}