RSCG – NetEscapades.EnumGenerators

RSCG – NetEscapades.EnumGenerators
 
 

name NetEscapades.EnumGenerators
nuget https://www.nuget.org/packages/NetEscapades.EnumGenerators/
link https://andrewlock.net/netescapades-enumgenerators-a-source-generator-for-enum-performance/
author Andrew Lock

Running fast tostring and other features for enum

 

This is how you can use NetEscapades.EnumGenerators .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NetEscapades.EnumGenerators" Version="1.0.0-beta08" 
					  OutputItemType="Analyzer" ReferenceOutputAssembly="false"
					  PrivateAssets="all" ExcludeAssets="comile;runtime"
					  />
  </ItemGroup>
 <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
  
</Project>


The code that you will use is



var value = InstallType.ShowGUI;
Console.WriteLine($"the enum string is {value.ToStringFast()}");
Console.WriteLine($"{InstallType.None.ToStringFast()}");


var flags = AddToCoffee.Milk | AddToCoffee.Sugar;

Console.WriteLine(flags.ToStringFast());
Console.WriteLine($"HasFlag(Milk), {flags.HasFlagFast(AddToCoffee.Milk)}");
Console.WriteLine($"HasFlag(Biscuit), {flags.HasFlagFast(AddToCoffee.Biscuit)}");
//check also
//InstallTypeExtensions.GetNames
//AddToCoffeeExtensions.GetNames


using NetEscapades.EnumGenerators;
using System.ComponentModel.DataAnnotations;
using System.Xml.Linq;

[EnumExtensions]
internal enum InstallType
{
    [Display(Name = $"Please use one of the flags of {nameof(InstallType)}")]
    None= 0,
    
    ShowGUI,
    ShowNoGui,
}



using NetEscapades.EnumGenerators;

[EnumExtensions]
[Flags]
internal enum AddToCoffee
{
    None= 0,
    Milk=1,
    Sugar=2,
    Biscuit=4
}

 

The code that is generated is

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the NetEscapades.EnumGenerators source generator
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable
#if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0
using System;
#endif

    /// <summary>
    /// Extension methods for <see cref="global::AddToCoffee" />
    /// </summary>
    internal static partial class AddToCoffeeExtensions
    {
        /// <summary>
        /// The number of members in the enum.
        /// This is a non-distinct count of defined names.
        /// </summary>
        public const int Length = 4;

        /// <summary>
        /// Returns the string representation of the <see cref="global::AddToCoffee"/> value.
        /// If the attribute is decorated with a <c>[Display]</c> attribute, then
        /// uses the provided value. Otherwise uses the name of the member, equivalent to
        /// calling <c>ToString()</c> on <paramref name="value"/>.
        /// </summary>
        /// <param name="value">The value to retrieve the string value for</param>
        /// <returns>The string representation of the value</returns>
        public static string ToStringFast(this global::AddToCoffee value)
            => value switch
            {
                global::AddToCoffee.None => nameof(global::AddToCoffee.None),
                global::AddToCoffee.Milk => nameof(global::AddToCoffee.Milk),
                global::AddToCoffee.Sugar => nameof(global::AddToCoffee.Sugar),
                global::AddToCoffee.Biscuit => nameof(global::AddToCoffee.Biscuit),
                _ => value.ToString(),
            };

        /// <summary>
        /// Determines whether one or more bit fields are set in the current instance.
        /// Equivalent to calling <see cref="global::System.Enum.HasFlag" /> on <paramref name="value"/>.
        /// </summary>
        /// <param name="value">The value of the instance to investigate</param>
        /// <param name="flag">The flag to check for</param>
        /// <returns><c>true</c> if the fields set in the flag are also set in the current instance; otherwise <c>false</c>.</returns>
        /// <remarks>If the underlying value of <paramref name="flag"/> is zero, the method returns true.
        /// This is consistent with the behaviour of <see cref="global::System.Enum.HasFlag" /></remarks>
        public static bool HasFlagFast(this global::AddToCoffee value, global::AddToCoffee flag)
            => flag == 0 ? true : (value & flag) == flag;

        /// <summary>
        /// Returns a boolean telling whether the given enum value exists in the enumeration.
        /// </summary>
        /// <param name="value">The value to check if it's defined</param>
        /// <returns><c>true</c> if the value exists in the enumeration, <c>false</c> otherwise</returns>
       public static bool IsDefined(global::AddToCoffee value)
            => value switch
            {
                global::AddToCoffee.None => true,
                global::AddToCoffee.Milk => true,
                global::AddToCoffee.Sugar => true,
                global::AddToCoffee.Biscuit => true,
                _ => false,
            };

        /// <summary>
        /// Returns a boolean telling whether an enum with the given name exists in the enumeration.
        /// </summary>
        /// <param name="name">The name to check if it's defined</param>
        /// <returns><c>true</c> if a member with the name exists in the enumeration, <c>false</c> otherwise</returns>
        public static bool IsDefined(string name) => IsDefined(name, allowMatchingMetadataAttribute: false);

        /// <summary>
        /// Returns a boolean telling whether an enum with the given name exists in the enumeration,
        /// or if a member decorated with a <c>[Display]</c> attribute
        /// with the required name exists.
        /// </summary>
        /// <param name="name">The name to check if it's defined</param>
        /// <param name="allowMatchingMetadataAttribute">If <c>true</c>, considers the value of metadata attributes,otherwise ignores them</param>
        /// <returns><c>true</c> if a member with the name exists in the enumeration, or a member is decorated
        /// with a <c>[Display]</c> attribute with the name, <c>false</c> otherwise</returns>
        public static bool IsDefined(string name, bool allowMatchingMetadataAttribute)
        {
            return name switch
            {
                nameof(global::AddToCoffee.None) => true,
                nameof(global::AddToCoffee.Milk) => true,
                nameof(global::AddToCoffee.Sugar) => true,
                nameof(global::AddToCoffee.Biscuit) => true,
                _ => false,
            };
        }

#if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0
        /// <summary>
        /// Returns a boolean telling whether an enum with the given name exists in the enumeration
        /// </summary>
        /// <param name="name">The name to check if it's defined</param>
        /// <returns><c>true</c> if a member with the name exists in the enumeration, <c>false</c> otherwise</returns>
        public static bool IsDefined(in ReadOnlySpan<char> name) => IsDefined(name, allowMatchingMetadataAttribute: false);

        /// <summary>
        /// Returns a boolean telling whether an enum with the given name exists in the enumeration,
        /// or optionally if a member decorated with a <c>[Display]</c> attribute
        /// with the required name exists.
        /// Slower then the <see cref="IsDefined(string, bool)" /> overload, but doesn't allocate memory./>
        /// </summary>
        /// <param name="name">The name to check if it's defined</param>
        /// <param name="allowMatchingMetadataAttribute">If <c>true</c>, considers the value of metadata attributes,otherwise ignores them</param>
        /// <returns><c>true</c> if a member with the name exists in the enumeration, or a member is decorated
        /// with a <c>[Display]</c> attribute with the name, <c>false</c> otherwise</returns>
        public static bool IsDefined(in ReadOnlySpan<char> name, bool allowMatchingMetadataAttribute)
        {
            return name switch
            {
                ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.None).AsSpan(), global::System.StringComparison.Ordinal) => true,
                ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.Milk).AsSpan(), global::System.StringComparison.Ordinal) => true,
                ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.Sugar).AsSpan(), global::System.StringComparison.Ordinal) => true,
                ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.Biscuit).AsSpan(), global::System.StringComparison.Ordinal) => true,
                _ => false,
            };
        }
#endif

        /// <summary>
        /// Converts the string representation of the name or numeric value of
        /// an <see cref="global::AddToCoffee" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The case-sensitive string representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::AddToCoffee" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::AddToCoffee" />. This parameter is passed uninitialized.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            string? name, 
            out global::AddToCoffee value)
            => TryParse(name, out value, false, false);

        /// <summary>
        /// Converts the string representation of the name or numeric value of
        /// an <see cref="global::AddToCoffee" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The string representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::AddToCoffee" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::AddToCoffee" />. This parameter is passed uninitialized.</param>
        /// <param name="ignoreCase"><c>true</c> to read value in case insensitive mode; <c>false</c> to read value in case sensitive mode.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            string? name, 
            out global::AddToCoffee value,
            bool ignoreCase) 
            => TryParse(name, out value, ignoreCase, false);

        /// <summary>
        /// Converts the string representation of the name or numeric value of
        /// an <see cref="global::AddToCoffee" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The string representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::AddToCoffee" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::AddToCoffee" />. This parameter is passed uninitialized.</param>
        /// <param name="ignoreCase"><c>true</c> to read value in case insensitive mode; <c>false</c> to read value in case sensitive mode.</param>
        /// <param name="allowMatchingMetadataAttribute">If <c>true</c>, considers the value included in metadata attributes such as
        /// <c>[Display]</c> attribute when parsing, otherwise only considers the member names.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            string? name, 
            out global::AddToCoffee value, 
            bool ignoreCase, 
            bool allowMatchingMetadataAttribute)
        {
            if (ignoreCase)
            {
                switch (name)
                {
                    case string s when s.Equals(nameof(global::AddToCoffee.None), global::System.StringComparison.OrdinalIgnoreCase):
                        value = global::AddToCoffee.None;
                        return true;
                    case string s when s.Equals(nameof(global::AddToCoffee.Milk), global::System.StringComparison.OrdinalIgnoreCase):
                        value = global::AddToCoffee.Milk;
                        return true;
                    case string s when s.Equals(nameof(global::AddToCoffee.Sugar), global::System.StringComparison.OrdinalIgnoreCase):
                        value = global::AddToCoffee.Sugar;
                        return true;
                    case string s when s.Equals(nameof(global::AddToCoffee.Biscuit), global::System.StringComparison.OrdinalIgnoreCase):
                        value = global::AddToCoffee.Biscuit;
                        return true;
                    case string s when int.TryParse(name, out var val):
                        value = (global::AddToCoffee)val;
                        return true;
                    default:
                        value = default;
                        return false;
                }
            }
            else
            {
                switch (name)
                {
                    case nameof(global::AddToCoffee.None):
                        value = global::AddToCoffee.None;
                        return true;
                    case nameof(global::AddToCoffee.Milk):
                        value = global::AddToCoffee.Milk;
                        return true;
                    case nameof(global::AddToCoffee.Sugar):
                        value = global::AddToCoffee.Sugar;
                        return true;
                    case nameof(global::AddToCoffee.Biscuit):
                        value = global::AddToCoffee.Biscuit;
                        return true;
                    case string s when int.TryParse(name, out var val):
                        value = (global::AddToCoffee)val;
                        return true;
                    default:
                        value = default;
                        return false;
                }
            }
        }

#if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0
        /// <summary>
        /// Converts the span representation of the name or numeric value of
        /// an <see cref="global::AddToCoffee" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The span representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::AddToCoffee" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::AddToCoffee" />. This parameter is passed uninitialized.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            in ReadOnlySpan<char> name, 
            out global::AddToCoffee value)
            => TryParse(name, out value, false, false);

        /// <summary>
        /// Converts the span representation of the name or numeric value of
        /// an <see cref="global::AddToCoffee" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The span representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::AddToCoffee" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::AddToCoffee" />. This parameter is passed uninitialized.</param>
        /// <param name="ignoreCase"><c>true</c> to read value in case insensitive mode; <c>false</c> to read value in case sensitive mode.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            in ReadOnlySpan<char> name, 
            out global::AddToCoffee value,
            bool ignoreCase) 
            => TryParse(name, out value, ignoreCase, false);

        /// <summary>
        /// Converts the span representation of the name or numeric value of
        /// an <see cref="global::AddToCoffee" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The span representation of the enumeration name or underlying value to convert</param>
        /// <param name="result">When this method returns, contains an object of type 
        /// <see cref="global::AddToCoffee" /> whose
        /// value is represented by <paramref name="result"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::AddToCoffee" />. This parameter is passed uninitialized.</param>
        /// <param name="ignoreCase"><c>true</c> to read value in case insensitive mode; <c>false</c> to read value in case sensitive mode.</param>
        /// <param name="allowMatchingMetadataAttribute">If <c>true</c>, considers the value included in metadata attributes such as
        /// <c>[Display]</c> attribute when parsing, otherwise only considers the member names.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            in ReadOnlySpan<char> name, 
            out global::AddToCoffee result, 
            bool ignoreCase,             
            bool allowMatchingMetadataAttribute)
        {
            if (ignoreCase)
            {
                switch (name)
                {
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.None).AsSpan(), global::System.StringComparison.OrdinalIgnoreCase):
                        result = global::AddToCoffee.None;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.Milk).AsSpan(), global::System.StringComparison.OrdinalIgnoreCase):
                        result = global::AddToCoffee.Milk;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.Sugar).AsSpan(), global::System.StringComparison.OrdinalIgnoreCase):
                        result = global::AddToCoffee.Sugar;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.Biscuit).AsSpan(), global::System.StringComparison.OrdinalIgnoreCase):
                        result = global::AddToCoffee.Biscuit;
                        return true;
                    case ReadOnlySpan<char> current when int.TryParse(name, out var numericResult):
                        result = (global::AddToCoffee)numericResult;
                        return true;
                    default:
                        result = default;
                        return false;
                }
            }
            else
            {
                switch (name)
                {
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.None).AsSpan(), global::System.StringComparison.Ordinal):
                        result = global::AddToCoffee.None;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.Milk).AsSpan(), global::System.StringComparison.Ordinal):
                        result = global::AddToCoffee.Milk;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.Sugar).AsSpan(), global::System.StringComparison.Ordinal):
                        result = global::AddToCoffee.Sugar;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::AddToCoffee.Biscuit).AsSpan(), global::System.StringComparison.Ordinal):
                        result = global::AddToCoffee.Biscuit;
                        return true;
                    case ReadOnlySpan<char> current when int.TryParse(name, out var numericResult):
                        result = (global::AddToCoffee)numericResult;
                        return true;
                    default:
                        result = default;
                        return false;
                }
            }
        }
#endif

        /// <summary>
        /// Retrieves an array of the values of the members defined in
        /// <see cref="global::AddToCoffee" />.
        /// Note that this returns a new array with every invocation, so
        /// should be cached if appropriate.
        /// </summary>
        /// <returns>An array of the values defined in <see cref="global::AddToCoffee" /></returns>
        public static global::AddToCoffee[] GetValues()
        {
            return new[]
            {
                global::AddToCoffee.None,
                global::AddToCoffee.Milk,
                global::AddToCoffee.Sugar,
                global::AddToCoffee.Biscuit,
            };
        }

        /// <summary>
        /// Retrieves an array of the names of the members defined in
        /// <see cref="global::AddToCoffee" />.
        /// Note that this returns a new array with every invocation, so
        /// should be cached if appropriate.
        /// </summary>
        /// <returns>An array of the names of the members defined in <see cref="global::AddToCoffee" /></returns>
        public static string[] GetNames()
        {
            return new[]
            {
                nameof(global::AddToCoffee.None),
                nameof(global::AddToCoffee.Milk),
                nameof(global::AddToCoffee.Sugar),
                nameof(global::AddToCoffee.Biscuit),
            };
        }
    }
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the NetEscapades.EnumGenerators source generator
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

#if NETESCAPADES_ENUMGENERATORS_EMBED_ATTRIBUTES
namespace NetEscapades.EnumGenerators
{
    /// <summary>
    /// Add to enums to indicate that extension methods should be generated for the type
    /// </summary>
    [global::System.AttributeUsage(global::System.AttributeTargets.Enum)]
    [global::System.Diagnostics.Conditional("NETESCAPADES_ENUMGENERATORS_USAGES")]
#if NET5_0_OR_GREATER
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage(Justification = "Generated by the NetEscapades.EnumGenerators source generator.")]
#else
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
#endif
    public class EnumExtensionsAttribute : global::System.Attribute
    {
        /// <summary>
        /// The namespace to generate the extension class.
        /// If not provided the namespace of the enum will be used
        /// </summary>
        public string? ExtensionClassNamespace { get; set; }

        /// <summary>
        /// The name to use for the extension class.
        /// If not provided, the enum name with "Extensions" will be used.
        /// For example for an Enum called StatusCodes, the default name
        /// will be StatusCodesExtensions
        /// </summary>
        public string? ExtensionClassName { get; set; }
    }
}
#endif

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by the NetEscapades.EnumGenerators source generator
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable
#if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0
using System;
#endif

    /// <summary>
    /// Extension methods for <see cref="global::InstallType" />
    /// </summary>
    internal static partial class InstallTypeExtensions
    {
        /// <summary>
        /// The number of members in the enum.
        /// This is a non-distinct count of defined names.
        /// </summary>
        public const int Length = 3;

        /// <summary>
        /// Returns the string representation of the <see cref="global::InstallType"/> value.
        /// If the attribute is decorated with a <c>[Display]</c> attribute, then
        /// uses the provided value. Otherwise uses the name of the member, equivalent to
        /// calling <c>ToString()</c> on <paramref name="value"/>.
        /// </summary>
        /// <param name="value">The value to retrieve the string value for</param>
        /// <returns>The string representation of the value</returns>
        public static string ToStringFast(this global::InstallType value)
            => value switch
            {
                global::InstallType.None => "Please use one of the flags of InstallType",
                global::InstallType.ShowGUI => nameof(global::InstallType.ShowGUI),
                global::InstallType.ShowNoGui => nameof(global::InstallType.ShowNoGui),
                _ => value.ToString(),
            };

        /// <summary>
        /// Returns a boolean telling whether the given enum value exists in the enumeration.
        /// </summary>
        /// <param name="value">The value to check if it's defined</param>
        /// <returns><c>true</c> if the value exists in the enumeration, <c>false</c> otherwise</returns>
       public static bool IsDefined(global::InstallType value)
            => value switch
            {
                global::InstallType.None => true,
                global::InstallType.ShowGUI => true,
                global::InstallType.ShowNoGui => true,
                _ => false,
            };

        /// <summary>
        /// Returns a boolean telling whether an enum with the given name exists in the enumeration.
        /// </summary>
        /// <param name="name">The name to check if it's defined</param>
        /// <returns><c>true</c> if a member with the name exists in the enumeration, <c>false</c> otherwise</returns>
        public static bool IsDefined(string name) => IsDefined(name, allowMatchingMetadataAttribute: false);

        /// <summary>
        /// Returns a boolean telling whether an enum with the given name exists in the enumeration,
        /// or if a member decorated with a <c>[Display]</c> attribute
        /// with the required name exists.
        /// </summary>
        /// <param name="name">The name to check if it's defined</param>
        /// <param name="allowMatchingMetadataAttribute">If <c>true</c>, considers the value of metadata attributes,otherwise ignores them</param>
        /// <returns><c>true</c> if a member with the name exists in the enumeration, or a member is decorated
        /// with a <c>[Display]</c> attribute with the name, <c>false</c> otherwise</returns>
        public static bool IsDefined(string name, bool allowMatchingMetadataAttribute)
        {
            var isDefinedInDisplayAttribute = false;
            if (allowMatchingMetadataAttribute)
            {
                isDefinedInDisplayAttribute = name switch
                {
                    "Please use one of the flags of InstallType" => true,
                    _ => false,
                };
            }

            if (isDefinedInDisplayAttribute)
            {
                return true;
            }

            
            return name switch
            {
                nameof(global::InstallType.None) => true,
                nameof(global::InstallType.ShowGUI) => true,
                nameof(global::InstallType.ShowNoGui) => true,
                _ => false,
            };
        }

#if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0
        /// <summary>
        /// Returns a boolean telling whether an enum with the given name exists in the enumeration
        /// </summary>
        /// <param name="name">The name to check if it's defined</param>
        /// <returns><c>true</c> if a member with the name exists in the enumeration, <c>false</c> otherwise</returns>
        public static bool IsDefined(in ReadOnlySpan<char> name) => IsDefined(name, allowMatchingMetadataAttribute: false);

        /// <summary>
        /// Returns a boolean telling whether an enum with the given name exists in the enumeration,
        /// or optionally if a member decorated with a <c>[Display]</c> attribute
        /// with the required name exists.
        /// Slower then the <see cref="IsDefined(string, bool)" /> overload, but doesn't allocate memory./>
        /// </summary>
        /// <param name="name">The name to check if it's defined</param>
        /// <param name="allowMatchingMetadataAttribute">If <c>true</c>, considers the value of metadata attributes,otherwise ignores them</param>
        /// <returns><c>true</c> if a member with the name exists in the enumeration, or a member is decorated
        /// with a <c>[Display]</c> attribute with the name, <c>false</c> otherwise</returns>
        public static bool IsDefined(in ReadOnlySpan<char> name, bool allowMatchingMetadataAttribute)
        {
            var isDefinedInDisplayAttribute = false;
            if (allowMatchingMetadataAttribute)
            {
                isDefinedInDisplayAttribute = name switch
                {
                    ReadOnlySpan<char> current when current.Equals("Please use one of the flags of InstallType".AsSpan(), global::System.StringComparison.Ordinal) => true,
                    _ => false,
                };
            }

            if (isDefinedInDisplayAttribute)
            {
                return true;
            }

            return name switch
            {
                ReadOnlySpan<char> current when current.Equals(nameof(global::InstallType.None).AsSpan(), global::System.StringComparison.Ordinal) => true,
                ReadOnlySpan<char> current when current.Equals(nameof(global::InstallType.ShowGUI).AsSpan(), global::System.StringComparison.Ordinal) => true,
                ReadOnlySpan<char> current when current.Equals(nameof(global::InstallType.ShowNoGui).AsSpan(), global::System.StringComparison.Ordinal) => true,
                _ => false,
            };
        }
#endif

        /// <summary>
        /// Converts the string representation of the name or numeric value of
        /// an <see cref="global::InstallType" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The case-sensitive string representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::InstallType" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::InstallType" />. This parameter is passed uninitialized.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            string? name, 
            out global::InstallType value)
            => TryParse(name, out value, false, false);

        /// <summary>
        /// Converts the string representation of the name or numeric value of
        /// an <see cref="global::InstallType" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The string representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::InstallType" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::InstallType" />. This parameter is passed uninitialized.</param>
        /// <param name="ignoreCase"><c>true</c> to read value in case insensitive mode; <c>false</c> to read value in case sensitive mode.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            string? name, 
            out global::InstallType value,
            bool ignoreCase) 
            => TryParse(name, out value, ignoreCase, false);

        /// <summary>
        /// Converts the string representation of the name or numeric value of
        /// an <see cref="global::InstallType" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The string representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::InstallType" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::InstallType" />. This parameter is passed uninitialized.</param>
        /// <param name="ignoreCase"><c>true</c> to read value in case insensitive mode; <c>false</c> to read value in case sensitive mode.</param>
        /// <param name="allowMatchingMetadataAttribute">If <c>true</c>, considers the value included in metadata attributes such as
        /// <c>[Display]</c> attribute when parsing, otherwise only considers the member names.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            string? name, 
            out global::InstallType value, 
            bool ignoreCase, 
            bool allowMatchingMetadataAttribute)
        {
            if (allowMatchingMetadataAttribute)
            {
                if (ignoreCase)
                {
                    switch (name)
                    {
                        case string s when s.Equals("Please use one of the flags of InstallType", global::System.StringComparison.OrdinalIgnoreCase):
                            value = global::InstallType.None;
                            return true;
                        default:
                            break;
                    };
                }
                else
                {
                    switch (name)
                    {
                        case "Please use one of the flags of InstallType":
                            value = global::InstallType.None;
                            return true;
                        default:
                            break;
                    };
                }
            }

            if (ignoreCase)
            {
                switch (name)
                {
                    case string s when s.Equals(nameof(global::InstallType.None), global::System.StringComparison.OrdinalIgnoreCase):
                        value = global::InstallType.None;
                        return true;
                    case string s when s.Equals(nameof(global::InstallType.ShowGUI), global::System.StringComparison.OrdinalIgnoreCase):
                        value = global::InstallType.ShowGUI;
                        return true;
                    case string s when s.Equals(nameof(global::InstallType.ShowNoGui), global::System.StringComparison.OrdinalIgnoreCase):
                        value = global::InstallType.ShowNoGui;
                        return true;
                    case string s when int.TryParse(name, out var val):
                        value = (global::InstallType)val;
                        return true;
                    default:
                        value = default;
                        return false;
                }
            }
            else
            {
                switch (name)
                {
                    case nameof(global::InstallType.None):
                        value = global::InstallType.None;
                        return true;
                    case nameof(global::InstallType.ShowGUI):
                        value = global::InstallType.ShowGUI;
                        return true;
                    case nameof(global::InstallType.ShowNoGui):
                        value = global::InstallType.ShowNoGui;
                        return true;
                    case string s when int.TryParse(name, out var val):
                        value = (global::InstallType)val;
                        return true;
                    default:
                        value = default;
                        return false;
                }
            }
        }

#if NETCOREAPP && !NETCOREAPP2_0 && !NETCOREAPP1_1 && !NETCOREAPP1_0
        /// <summary>
        /// Converts the span representation of the name or numeric value of
        /// an <see cref="global::InstallType" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The span representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::InstallType" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::InstallType" />. This parameter is passed uninitialized.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            in ReadOnlySpan<char> name, 
            out global::InstallType value)
            => TryParse(name, out value, false, false);

        /// <summary>
        /// Converts the span representation of the name or numeric value of
        /// an <see cref="global::InstallType" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The span representation of the enumeration name or underlying value to convert</param>
        /// <param name="value">When this method returns, contains an object of type 
        /// <see cref="global::InstallType" /> whose
        /// value is represented by <paramref name="value"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::InstallType" />. This parameter is passed uninitialized.</param>
        /// <param name="ignoreCase"><c>true</c> to read value in case insensitive mode; <c>false</c> to read value in case sensitive mode.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            in ReadOnlySpan<char> name, 
            out global::InstallType value,
            bool ignoreCase) 
            => TryParse(name, out value, ignoreCase, false);

        /// <summary>
        /// Converts the span representation of the name or numeric value of
        /// an <see cref="global::InstallType" /> to the equivalent instance.
        /// The return value indicates whether the conversion succeeded.
        /// </summary>
        /// <param name="name">The span representation of the enumeration name or underlying value to convert</param>
        /// <param name="result">When this method returns, contains an object of type 
        /// <see cref="global::InstallType" /> whose
        /// value is represented by <paramref name="result"/> if the parse operation succeeds.
        /// If the parse operation fails, contains the default value of the underlying type
        /// of <see cref="global::InstallType" />. This parameter is passed uninitialized.</param>
        /// <param name="ignoreCase"><c>true</c> to read value in case insensitive mode; <c>false</c> to read value in case sensitive mode.</param>
        /// <param name="allowMatchingMetadataAttribute">If <c>true</c>, considers the value included in metadata attributes such as
        /// <c>[Display]</c> attribute when parsing, otherwise only considers the member names.</param>
        /// <returns><c>true</c> if the value parameter was converted successfully; otherwise, <c>false</c>.</returns>
        public static bool TryParse(
#if NETCOREAPP3_0_OR_GREATER
            [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
            in ReadOnlySpan<char> name, 
            out global::InstallType result, 
            bool ignoreCase,             
            bool allowMatchingMetadataAttribute)
        {
            if (allowMatchingMetadataAttribute)
            {
                if (ignoreCase)
                {
                    switch (name)
                    {
                        case ReadOnlySpan<char> current when current.Equals("Please use one of the flags of InstallType".AsSpan(), global::System.StringComparison.OrdinalIgnoreCase):
                            result = global::InstallType.None;
                            return true;
                        default:
                            break;
                    };
                }
                else
                {
                    switch (name)
                    {
                        case ReadOnlySpan<char> current when current.Equals("Please use one of the flags of InstallType".AsSpan(), global::System.StringComparison.Ordinal):
                            result = global::InstallType.None;
                            return true;
                        default:
                            break;
                    };
                }
            }

            if (ignoreCase)
            {
                switch (name)
                {
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::InstallType.None).AsSpan(), global::System.StringComparison.OrdinalIgnoreCase):
                        result = global::InstallType.None;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::InstallType.ShowGUI).AsSpan(), global::System.StringComparison.OrdinalIgnoreCase):
                        result = global::InstallType.ShowGUI;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::InstallType.ShowNoGui).AsSpan(), global::System.StringComparison.OrdinalIgnoreCase):
                        result = global::InstallType.ShowNoGui;
                        return true;
                    case ReadOnlySpan<char> current when int.TryParse(name, out var numericResult):
                        result = (global::InstallType)numericResult;
                        return true;
                    default:
                        result = default;
                        return false;
                }
            }
            else
            {
                switch (name)
                {
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::InstallType.None).AsSpan(), global::System.StringComparison.Ordinal):
                        result = global::InstallType.None;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::InstallType.ShowGUI).AsSpan(), global::System.StringComparison.Ordinal):
                        result = global::InstallType.ShowGUI;
                        return true;
                    case ReadOnlySpan<char> current when current.Equals(nameof(global::InstallType.ShowNoGui).AsSpan(), global::System.StringComparison.Ordinal):
                        result = global::InstallType.ShowNoGui;
                        return true;
                    case ReadOnlySpan<char> current when int.TryParse(name, out var numericResult):
                        result = (global::InstallType)numericResult;
                        return true;
                    default:
                        result = default;
                        return false;
                }
            }
        }
#endif

        /// <summary>
        /// Retrieves an array of the values of the members defined in
        /// <see cref="global::InstallType" />.
        /// Note that this returns a new array with every invocation, so
        /// should be cached if appropriate.
        /// </summary>
        /// <returns>An array of the values defined in <see cref="global::InstallType" /></returns>
        public static global::InstallType[] GetValues()
        {
            return new[]
            {
                global::InstallType.None,
                global::InstallType.ShowGUI,
                global::InstallType.ShowNoGui,
            };
        }

        /// <summary>
        /// Retrieves an array of the names of the members defined in
        /// <see cref="global::InstallType" />.
        /// Note that this returns a new array with every invocation, so
        /// should be cached if appropriate.
        /// </summary>
        /// <returns>An array of the names of the members defined in <see cref="global::InstallType" /></returns>
        public static string[] GetNames()
        {
            return new[]
            {
                nameof(global::InstallType.None),
                nameof(global::InstallType.ShowGUI),
                nameof(global::InstallType.ShowNoGui),
            };
        }
    }

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/NetEscapades.EnumGenerators