JOS.Enumeration 4.0.2

There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package JOS.Enumeration --version 4.0.2                
NuGet\Install-Package JOS.Enumeration -Version 4.0.2                
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="JOS.Enumeration" Version="4.0.2" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add JOS.Enumeration --version 4.0.2                
#r "nuget: JOS.Enumeration, 4.0.2"                
#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 JOS.Enumeration as a Cake Addin
#addin nuget:?package=JOS.Enumeration&version=4.0.2

// Install JOS.Enumeration as a Cake Tool
#tool nuget:?package=JOS.Enumeration&version=4.0.2                

JOS.Enumeration

Enumeration implementation with source generation support.

Installation

JOS.Enumeration

Contains the IEnumeration interface and a System.Text.Json JsonConverter. The JOS.Enumeration.SourceGenerator package contains the actual source generator.

Don't forget to install that one as well. 😃

dotnet add package JOS.Enumeration
dotnet add package JOS.Enumeration.SourceGenerator

JOS.Enumeration.Database.Dapper

Contains a custom TypeHandler to use with Dapper.

dotnet add package JOS.Enumeration.Database.Dapper

JOS.Enumeration.Database.EntityFrameworkCore

Contains ConfigureEnumeration extension method to allow usage with EntityFramework Core.

dotnet add package JOS.Enumeration.Database.EntityFrameworkCore

Usage

  • Create a new partial record or class
  • Implement the IEnumeration<T> interface
  • Add your Enumeration items
public partial record Hamburger : IEnumeration<Hamburger>
{
    public static readonly Hamburger Cheeseburger = new (1, "Cheeseburger");
    public static readonly Hamburger BigMac = new(2, "Big Mac");
    public static readonly Hamburger BigTasty = new(3, "Big Tasty");
}

The source generator will implement the following interface:

// Default implementation -> int as Value
public interface IEnumeration<T> : IEnumeration<int, T> where T : IEnumeration<T>
{
}

public interface IEnumeration<TValue, TType> where TValue : IConvertible
{
    TValue Value { get; }
    string Description { get; }
    static abstract IReadOnlySet<TType> GetAll();
    static abstract IEnumerable<TType> GetEnumerable();
    static abstract TType FromValue(TValue value);
    static abstract TType FromDescription(string description);
    static abstract TType FromDescription(ReadOnlySpan<char> description);
    static abstract Type ValueType { get; }
}

The following code will be generated:

[System.Diagnostics.DebuggerDisplay("{Description}")]
public partial record Hamburger : IComparable<JOS.Enumerations.Hamburger>
{
    private static readonly IReadOnlySet<JOS.Enumerations.Hamburger> AllItems;
    
    static Hamburger()
    {
        AllItems = new HashSet<JOS.Enumerations.Hamburger>(3)
        {
            Cheeseburger,
            BigMac,
            BigTasty
        }.ToFrozenSet(optimizeForReading: true);
    }

    private Hamburger(int value, string description)
    {
        Value = value;
        Description = description ?? throw new ArgumentNullException(nameof(description));
    }

    public int Value { get; }

    public string Description { get; }

    public static IReadOnlySet<JOS.Enumerations.Hamburger> GetAll()
    {
        return AllItems;
    }

    public static IEnumerable<JOS.Enumerations.Hamburger> GetEnumerable()
    {
        yield return Cheeseburger;
        yield return BigMac;
        yield return BigTasty;
    }

    public static JOS.Enumerations.Hamburger FromValue(int value)
    {
        return value switch
        {
            1 => Cheeseburger,
            2 => BigMac,
            3 => BigTasty,
            _ => throw new InvalidOperationException($"'{value}' is not a valid value in 'JOS.Enumerations.Hamburger'")
        };
    }

    public static JOS.Enumerations.Hamburger FromDescription(string description)
    {
        return description switch
        {
            "Cheeseburger" => Cheeseburger,
            "Big Mac" => BigMac,
            "Big Tasty" => BigTasty,
            _ => throw new InvalidOperationException($"'{description}' is not a valid description in 'JOS.Enumerations.Hamburger'")
        };
    }

    public static JOS.Enumerations.Hamburger FromDescription(ReadOnlySpan<char> description)
    {
        return description switch
        {
            "Cheeseburger" => Cheeseburger,
            "Big Mac" => BigMac,
            "Big Tasty" => BigTasty,
            _ => throw new InvalidOperationException($"'{description}' is not a valid description in 'JOS.Enumerations.Hamburger'")
        };
    }

    public static Type ValueType => typeof(int);
    public int CompareTo(JOS.Enumerations.Hamburger? other) => Value.CompareTo(other!.Value);
    public static implicit operator int (JOS.Enumerations.Hamburger item) => item.Value;
    public static implicit operator JOS.Enumerations.Hamburger(int value) => FromValue(value);
}

Features

  • Generic value
  • Generated IComparable<T> method.
  • Generated implicit operators (convert to/from int).
  • Generated optimized GetAll, FromValue and FromDescription methods.
  • System.Text.Json support
  • Database support (Dapper and EF Core).

Generic value

It's possible to use a generic value instead of the default int value by implementing the IEnumeration<TValue, TEnumeration> interface.

public partial record Car : IEnumeration<string, Car>
{
    public static readonly Car FerrariSpider = new("ferrari-spider", "Ferrari Spider");
    public static readonly Car TeslaModelY = new("tesla-model-y", "Tesla Model Y");
}

TValue has a IConvertible constraint.

The following types has been tested and are guaranteed to work:

  • int (default)
  • bool
  • decimal
  • long
  • string
  • uint
  • ulong

JSON

The package comes with a generic JsonConverter. You'll need to register a custom converter for each enumeration. Example:

var jsonSerializerOptions = new JsonSerializerOptions
{
    Converters = { new EnumerationJsonConverter<Hamburger>() }
};

If you're using a custom value, you need to register the converter like this:

var jsonSerializerOptions = new JsonSerializerOptions
{
    Converters = { new EnumerationJsonConverter<string, Car>() }
};

It supports the following scenarios:

  • Serializing to TValue
  • Deserializing from TValue

If you want any other behaviour, just create your own converter and register it.

Database

public class MyEntity
{
    public MyEntity(Guid id, Hamburger hamburger)
    {
        Id = id;
        Hamburger = hamburger;
    }

    public Guid Id { get; }
    public Hamburger Hamburger { get; }
}
Dapper
  • Register the TypeHandler: SqlMapper.AddTypeHandler(new EnumerationTypeHandler<Hamburger>())
  • Query like this:
var results = (await actConnection.QueryAsync<MyEntity>(
            "SELECT id, hamburger from my_entities WHERE id = @id", new {id = myEntity.Id})).ToList(); 
EF Core
  • Configure your DB Context
public DbSet<MyEntity> MyEntities { get; set; } = null!;

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfigurationsFromAssembly(typeof(JosEnumerationDbContext).Assembly);
} 
public class MyEntityEntityTypeConfiguration : IEntityTypeConfiguration<MyEntity>
{
    public void Configure(EntityTypeBuilder<MyEntity> builder)
    {
        builder.HasKey(x => x.Id);
        builder.Property(x => x.Hamburger).ConfigureEnumeration().IsRequired();
    }
}
  • Query:
var result = await myDbContext.MyEntities.FirstAsync(x => x.Id == myEntity.Id); 

Primitive Collections

Support for primitive collections in net8.0 can be configured like this:

EF Core
public void Configure(EntityTypeBuilder<MyEntity> builder)
{
    builder.ConfigureEnumeration<MyEntity, string, Car>(x => x.Cars);
}
Dapper
SqlMapper.AddTypeHandler(new EnumerationArrayTypeHandler<string, Car>());
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.  net9.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on JOS.Enumeration:

Package Downloads
JOS.Enumeration.Database.Dapper

Package Description

JOS.Enumeration.Database.EntityFrameworkCore

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.1.14-beta-gc2ddf8f752 66 12/2/2024
4.1.13-beta-g0df3582c0d 62 12/2/2024
4.1.12-beta-g97ccd40129 69 12/2/2024
4.1.9-beta-g6ffe24327b 68 12/2/2024
4.1.8-beta-g415eb19bd8 70 12/2/2024
4.1.7-beta-gdb2f2831d6 70 12/2/2024
4.1.6-beta-gef2489413a 86 12/2/2024
4.1.5-beta-g6b481c8235 78 11/28/2024
4.1.3-beta-g6c6fa8e7f6 70 11/28/2024
4.1.2-beta-g94dcadc76c 72 11/28/2024
4.0.2 209 11/28/2024
3.1.4-beta-g80cdfd1869 67 11/26/2024
3.1.3-beta-g5539fda0e8 76 11/15/2024
3.1.2-beta-gad970619af 67 11/15/2024
2.0.8-beta-g72852e0cc9 76 11/8/2024
2.0.7-beta-g1c736f7cbd 67 11/7/2024
2.0.6-beta-g33fdc165e1 109 11/7/2024
2.0.5-beta-g4df623a3fd 100 9/17/2024
2.0.4-beta-g41a385195d 95 9/17/2024
2.0.3-beta-g1b3ff0345c 81 9/17/2024
1.3.5-beta-ga3591d0784 164 1/8/2024
1.3.4-beta-g0f657b5945 172 12/15/2023
1.3.3-beta-g86c57c88de 161 12/6/2023
1.3.2-beta-g44904a2c86 149 12/6/2023
1.2.10 318 1/8/2024
1.2.9 222 12/6/2023
1.2.8-beta-g7f4afbc7bc 139 12/6/2023
1.2.7-beta-g8c3c1bea8d 158 12/5/2023
1.2.6-beta-gaceb5947a0 138 12/3/2023
1.2.5-beta-gd88393f87f 157 11/21/2023
1.2.4-beta-gcf63299055 145 11/14/2023
1.2.3-beta-g17d841819f 125 11/14/2023
1.2.2-beta-g48b6b63682 131 11/14/2023
1.1.37 292 11/14/2023
1.1.36-beta-g300cca1b1c 115 11/14/2023
1.1.34-beta-gbd8240dec5 133 11/4/2023
1.1.19-beta-g0616c54bd7 171 7/14/2023
1.1.18-beta-g196c9ec97b 136 7/14/2023
1.1.16-beta-g9ebac3a201 135 7/14/2023
1.1.15-beta-g6aa862b5fa 122 7/14/2023
1.1.14-beta-gd3f3eff596 124 7/14/2023
1.1.13-beta-gaae338e581 125 7/14/2023
1.1.11-beta-gedc10e9f0b 155 7/11/2023
1.1.10-beta-g15d758679f 118 7/11/2023
1.1.9-beta-ga8f5b4d09c 142 7/11/2023
1.1.8-beta-gbe35470ba8 134 7/11/2023
1.1.7-beta-g4edda95a99 153 6/20/2023
1.1.6-beta-gad8ab8816a 138 6/20/2023
1.1.5-beta-g02ae57f212 134 6/19/2023
1.1.4-beta-g2b6e2e274f 148 6/18/2023
1.1.3-beta-gfef378b783 143 6/18/2023
1.1.2-beta-gb3750f4659 140 6/17/2023
1.0.13-beta-g4bac5970df 158 6/17/2023
1.0.12-beta-g5e554e74de 135 6/17/2023
1.0.11-beta-ge0c0ac2086 164 6/17/2023 1.0.11-beta-ge0c0ac2086 is deprecated.
1.0.10-beta-gcbaa073338 164 6/17/2023 1.0.10-beta-gcbaa073338 is deprecated.
1.0.9-beta-g9bac00482d 169 6/17/2023 1.0.9-beta-g9bac00482d is deprecated.
1.0.8-beta-gec072ace6a 174 6/17/2023 1.0.8-beta-gec072ace6a is deprecated.
1.0.6-beta-g3f377c1cfc 152 6/17/2023 1.0.6-beta-g3f377c1cfc is deprecated.
1.0.4-beta-g35471cdafc 164 6/17/2023 1.0.4-beta-g35471cdafc is deprecated.