Category: .NET 7

RSCG – PrimaryParameter

RSCG – PrimaryParameter    

name PrimaryParameter
nuget https://www.nuget.org/packages/FaustVX.PrimaryParameter.SG
link https://github.com/FaustVX/PrimaryParameter
author FaustVX

Generating properties from .NET 8 constructor parameters

 

This is how you can use PrimaryParameter .

The code that you start with is

  <Project Sdk="Microsoft.NET.Sdk">    <PropertyGroup>     <OutputType>Exe</OutputType>     <TargetFramework>net8.0</TargetFramework>     <ImplicitUsings>enable</ImplicitUsings>     <Nullable>enable</Nullable>   </PropertyGroup>  	<PropertyGroup> 		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles> 		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath> 	</PropertyGroup>  	<ItemGroup> 	  <PackageReference Include="FaustVX.PrimaryParameter.SG" Version="1.2.0" OutputItemType="Analyzer" ReferenceOutputAssembly="false"  /> 	</ItemGroup> </Project>   

The code that you will use is

  using QuickConstructorDemo;  var p = new Person("Andrei", "Ignat");  Console.WriteLine(p.FullName());  
  using PrimaryParameter.SG; namespace QuickConstructorDemo; internal partial class Person([Property]string FirstName,[Field(Name ="_LastName",Scope ="public")]string? LastName=null) {     //private readonly string FirstName;     //private readonly string? LastName;          public string FullName() => $"{FirstName} {_LastName}";      }   

  The code that is generated is

 namespace QuickConstructorDemo {     partial class Person     {         public string FirstName { get; init; } = FirstName;     } } namespace QuickConstructorDemo {     partial class Person     {         public readonly string _LastName = LastName;     } }  
 using global::System; namespace PrimaryParameter.SG {     [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = true)]     sealed class FieldAttribute : Attribute     {         public string Name { get; init; }         public string AssignFormat { get; init; }         public Type Type { get; init; }         public bool IsReadonly { get; init; }         public string Scope { get; init; }     } } 
 using global::System; namespace PrimaryParameter.SG {     [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = true)]     sealed class PropertyAttribute : Attribute     {         public string Name { get; init; }         public string AssignFormat { get; init; }         public Type Type { get; init; }         public bool WithInit { get; init; }         public string Scope { get; init; }     } } 
 using global::System; namespace PrimaryParameter.SG {     [AttributeUsage(AttributeTargets.Parameter, Inherited = false, AllowMultiple = true)]     sealed class RefFieldAttribute : Attribute     {         public string Name { get; init; }         public string Scope { get; init; }         public bool IsReadonlyRef { get; init; }         public bool IsRefReadonly { get; init; }     } } 

Code and pdf at https://ignatandrei.github.io/RSCG_Examples/v2/docs/PrimaryParameter

RSCG – jsonConverterSourceGenerator

RSCG – jsonConverterSourceGenerator    

name jsonConverterSourceGenerator
nuget https://www.nuget.org/packages/Aviationexam.GeneratedJsonConverters.SourceGenerator/
link https://github.com/aviationexam/json-converter-source-generator
author Aviationexam

Json Polymorphic generator

  

This is how you can use jsonConverterSourceGenerator .

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>
  </itemgroup>
	<itemgroup>
		<packagereference privateassets="all" version="0.1.11" include="Aviationexam.GeneratedJsonConverters.SourceGenerator">
	</packagereference>
	<propertygroup>
		<emitcompilergeneratedfiles>true</emitcompilergeneratedfiles>
		<compilergeneratedfilesoutputpath>$(BaseIntermediateOutputPath)\GX</compilergeneratedfilesoutputpath>
	</propertygroup>

</itemgroup>


The code that you will use is


//https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism?pivots=dotnet-7-0
using JsonPolymorphicGeneratorDemo;
using System.Text.Json;

Person[] persons = new Person[2];
persons[0] = new Student() { Name="Student Ignat"};

persons[1] = new Teacher() { Name = "Teacher Ignat" };
//JsonSerializerOptions opt = new ()
//{
//    WriteIndented = true
//};
//var ser = JsonSerializer.Serialize(persons, opt);

var ser = JsonSerializer.Serialize(persons, ProjectJsonSerializerContext.Default.Options);

Console.WriteLine(ser);
var p = JsonSerializer.Deserialize<person  &#91;&#93;>(ser,ProjectJsonSerializerContext.Default.Options);
if(p != null)
foreach (var item in p)
{
    Console.WriteLine(item.Data());
}



namespace JsonPolymorphicGeneratorDemo;

[Aviationexam.GeneratedJsonConverters.Attributes.JsonPolymorphic]
[Aviationexam.GeneratedJsonConverters.Attributes.JsonDerivedType(typeof(Student))]
[Aviationexam.GeneratedJsonConverters.Attributes.JsonDerivedType(typeof(Teacher))]
public abstract partial class Person
{
    
    public string? Name { get; set; }
    public abstract string Data();
}

public class Teacher : Person
{
    public override string Data()
    {
        return "Class Teacher:" + Name;
    }
}
public class Student : Person
{
    public override string Data()
    {
        return "Class Student:" + Name;
    }
}



//https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism?pivots=dotnet-7-0
using JsonPolymorphicGeneratorDemo;
using System.Text.Json.Serialization;

[JsonSourceGenerationOptions(
    WriteIndented = true,
    PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
    GenerationMode = JsonSourceGenerationMode.Default
)]
[JsonSerializable(typeof(Person[]))]
[JsonSerializable(typeof(Person))]
[JsonSerializable(typeof(Student))]
[JsonSerializable(typeof(Teacher))]
public partial class ProjectJsonSerializerContext : JsonSerializerContext
{
    static ProjectJsonSerializerContext()
    {
        foreach (var converter in GetPolymorphicConverters())
        {
            s_defaultOptions.Converters.Add(converter);
        }
    }
}

   The code that is generated is

// ReSharper disable once CheckNamespace
namespace Aviationexam.GeneratedJsonConverters.Attributes;

/// <summary>
/// When placed on an enum, indicates that generator should not report missing <see cref="EnumJsonConverterAttribute">
/// </see></summary>
[System.AttributeUsage(System.AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]
internal sealed class DisableEnumJsonConverterAttribute : System.Text.Json.Serialization.JsonAttribute
{
}

// ReSharper disable once RedundantNullableDirective

#nullable enable

using Aviationexam.GeneratedJsonConverters.Attributes;
using System;

namespace Aviationexam.GeneratedJsonConverters;

[Flags]
[DisableEnumJsonConverter]
internal enum EnumDeserializationStrategy : byte
{
    ProjectDefault = 0,
    UseBackingType = 1 &lt;&lt; 0,
    UseEnumName = 1 &lt;&lt; 1,
}

#nullable enable

namespace Aviationexam.GeneratedJsonConverters.Attributes;

/// <summary>
/// When placed on an enum, indicates that the type should be serialized using generated enum convertor.
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Enum, AllowMultiple = false, Inherited = false)]
internal sealed class EnumJsonConverterAttribute : System.Text.Json.Serialization.JsonAttribute
{
    /// <summary>
    /// Configure serialization strategy
    /// </summary>
    public EnumSerializationStrategy SerializationStrategy { get; set; } = EnumSerializationStrategy.ProjectDefault;

    /// <summary>
    /// Configure deserialization strategy
    /// </summary>
    public EnumDeserializationStrategy DeserializationStrategy { get; set; } = EnumDeserializationStrategy.ProjectDefault;
}
// ReSharper disable once RedundantNullableDirective

#nullable enable

using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Aviationexam.GeneratedJsonConverters;

internal abstract class EnumJsonConvertor<t  , tbackingtype=""> : JsonConverter<t>
    where T : struct, Enum
    where TBackingType : struct
{
    protected abstract TypeCode BackingTypeTypeCode { get; }

    protected abstract EnumDeserializationStrategy DeserializationStrategy { get; }

    protected abstract EnumSerializationStrategy SerializationStrategy { get; }

    public abstract bool TryToEnum(ReadOnlySpan<byte> enumName, out T value);

    public abstract bool TryToEnum(TBackingType numericValue, out T value);

    public abstract TBackingType ToBackingType(T value);

    public abstract ReadOnlySpan<byte> ToFirstEnumName(T value);

    public override T Read(
        ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options
    )
    {
        if (
            reader.TokenType is JsonTokenType.String
            &amp;&amp; DeserializationStrategy.HasFlag(EnumDeserializationStrategy.UseEnumName)
        )
        {
            var enumName = reader.ValueSpan;

            if (TryToEnum(enumName, out var enumValue))
            {
                return enumValue;
            }

            var stringValue = Encoding.UTF8.GetString(enumName.ToArray());

            throw new JsonException($"Undefined mapping of '{stringValue}' to enum '{typeof(T).FullName}'");
        }

        if (reader.TokenType is JsonTokenType.Number)
        {
            var numericValue = ReadAsNumber(ref reader);

            if (numericValue.HasValue)
            {
                if (TryToEnum(numericValue.Value, out var enumValue))
                {
                    return enumValue;
                }

                throw new JsonException($"Undefined mapping of '{numericValue}' to enum '{{enumFullName}}'");
            }
        }

        var value = Encoding.UTF8.GetString(reader.ValueSpan.ToArray());

        throw new JsonException($"Unable to deserialize {value}('{reader.TokenType}') into {typeof(T).Name}");
    }

    public override T ReadAsPropertyName(
        ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options
    )
    {
        if (
            reader.TokenType is JsonTokenType.PropertyName
            &amp;&amp; DeserializationStrategy.HasFlag(EnumDeserializationStrategy.UseEnumName)
        )
        {
            var enumName = reader.ValueSpan;

            if (TryToEnum(enumName, out var enumValue))
            {
                return enumValue;
            }
        }

        var value = Encoding.UTF8.GetString(reader.ValueSpan.ToArray());

        if (
            reader.TokenType is JsonTokenType.PropertyName
            &amp;&amp; DeserializationStrategy.HasFlag(EnumDeserializationStrategy.UseBackingType)
        )
        {
            var numericValue = ParseAsNumber(value);

            if (numericValue.HasValue)
            {
                if (TryToEnum(numericValue.Value, out var enumValue))
                {
                    return enumValue;
                }
            }
        }

        throw new JsonException($"Unable to deserialize {value}('{reader.TokenType}') into {typeof(T).Name}");
    }

    private TBackingType? ReadAsNumber(ref Utf8JsonReader reader) =&gt; BackingTypeTypeCode switch
    {
        TypeCode.SByte =&gt; reader.GetSByte() is var numericValue ? Unsafe.As<sbyte  , tbackingtype="">(ref numericValue) : null,
        TypeCode.Byte =&gt; reader.GetByte() is var numericValue ? Unsafe.As<byte  , tbackingtype="">(ref numericValue) : null,
        TypeCode.Int16 =&gt; reader.GetInt16() is var numericValue ? Unsafe.As<short  , tbackingtype="">(ref numericValue) : null,
        TypeCode.UInt16 =&gt; reader.GetUInt16() is var numericValue ? Unsafe.As<ushort  , tbackingtype="">(ref numericValue) : null,
        TypeCode.Int32 =&gt; reader.GetInt32() is var numericValue ? Unsafe.As<int  , tbackingtype="">(ref numericValue) : null,
        TypeCode.UInt32 =&gt; reader.GetUInt32() is var numericValue ? Unsafe.As<uint  , tbackingtype="">(ref numericValue) : null,
        TypeCode.Int64 =&gt; reader.GetInt64() is var numericValue ? Unsafe.As<long  , tbackingtype="">(ref numericValue) : null,
        TypeCode.UInt64 =&gt; reader.GetUInt64() is var numericValue ? Unsafe.As<ulong  , tbackingtype="">(ref numericValue) : null,
        _ =&gt; throw new ArgumentOutOfRangeException(nameof(BackingTypeTypeCode), BackingTypeTypeCode, $"Unexpected TypeCode {BackingTypeTypeCode}")
    };

    private TBackingType? ParseAsNumber(
        string value
    ) =&gt; BackingTypeTypeCode switch
    {
        TypeCode.SByte =&gt; sbyte.TryParse(value, out var numericValue) ? Unsafe.As<sbyte  , tbackingtype="">(ref numericValue) : null,
        TypeCode.Byte =&gt; byte.TryParse(value, out var numericValue) ? Unsafe.As<byte  , tbackingtype="">(ref numericValue) : null,
        TypeCode.Int16 =&gt; short.TryParse(value, out var numericValue) ? Unsafe.As<short  , tbackingtype="">(ref numericValue) : null,
        TypeCode.UInt16 =&gt; ushort.TryParse(value, out var numericValue) ? Unsafe.As<ushort  , tbackingtype="">(ref numericValue) : null,
        TypeCode.Int32 =&gt; int.TryParse(value, out var numericValue) ? Unsafe.As<int  , tbackingtype="">(ref numericValue) : null,
        TypeCode.UInt32 =&gt; uint.TryParse(value, out var numericValue) ? Unsafe.As<uint  , tbackingtype="">(ref numericValue) : null,
        TypeCode.Int64 =&gt; long.TryParse(value, out var numericValue) ? Unsafe.As<long  , tbackingtype="">(ref numericValue) : null,
        TypeCode.UInt64 =&gt; ulong.TryParse(value, out var numericValue) ? Unsafe.As<ulong  , tbackingtype="">(ref numericValue) : null,
        _ =&gt; throw new ArgumentOutOfRangeException(nameof(BackingTypeTypeCode), BackingTypeTypeCode, $"Unexpected TypeCode {BackingTypeTypeCode}")
    };

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        if (SerializationStrategy is EnumSerializationStrategy.BackingType)
        {
            WriteAsBackingType(writer, value, options);
        }
        else if (SerializationStrategy is EnumSerializationStrategy.FirstEnumName)
        {
            WriteAsFirstEnumName(writer, value, options);
        }
        else
        {
            throw new ArgumentOutOfRangeException(nameof(SerializationStrategy), SerializationStrategy, "Unknown serialization strategy");
        }
    }

    public override void WriteAsPropertyName(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        if (SerializationStrategy is EnumSerializationStrategy.BackingType)
        {
            WriteAsPropertyNameAsBackingType(writer, value, options);
        }
        else if (SerializationStrategy is EnumSerializationStrategy.FirstEnumName)
        {
            WriteAsPropertyNameAsFirstEnumName(writer, value, options);
        }
        else
        {
            throw new ArgumentOutOfRangeException(nameof(SerializationStrategy), SerializationStrategy, "Unknown serialization strategy");
        }
    }

    private void WriteAsBackingType(
        Utf8JsonWriter writer,
        T value,
        [SuppressMessage("ReSharper", "UnusedParameter.Local")]
        JsonSerializerOptions options
    )
    {
        var numericValue = ToBackingType(value);

        switch (BackingTypeTypeCode)
        {
            case TypeCode.SByte:
                writer.WriteNumberValue(Unsafe.As<tbackingtype  , sbyte="">(ref numericValue));
                break;
            case TypeCode.Byte:
                writer.WriteNumberValue(Unsafe.As<tbackingtype  , byte="">(ref numericValue));
                break;
            case TypeCode.Int16:
                writer.WriteNumberValue(Unsafe.As<tbackingtype  , short="">(ref numericValue));
                break;
            case TypeCode.UInt16:
                writer.WriteNumberValue(Unsafe.As<tbackingtype  , ushort="">(ref numericValue));
                break;
            case TypeCode.Int32:
                writer.WriteNumberValue(Unsafe.As<tbackingtype  , int="">(ref numericValue));
                break;
            case TypeCode.UInt32:
                writer.WriteNumberValue(Unsafe.As<tbackingtype  , uint="">(ref numericValue));
                break;
            case TypeCode.Int64:
                writer.WriteNumberValue(Unsafe.As<tbackingtype  , long="">(ref numericValue));
                break;
            case TypeCode.UInt64:
                writer.WriteNumberValue(Unsafe.As<tbackingtype  , ulong="">(ref numericValue));
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(BackingTypeTypeCode), BackingTypeTypeCode, $"Unexpected TypeCode {BackingTypeTypeCode}");
        }
    }

    private void WriteAsPropertyNameAsBackingType(
        Utf8JsonWriter writer,
        T value,
        [SuppressMessage("ReSharper", "UnusedParameter.Local")]
        JsonSerializerOptions options
    )
    {
        var numericValue = ToBackingType(value);

        writer.WritePropertyName($"{numericValue}");
    }

    private void WriteAsFirstEnumName(
        Utf8JsonWriter writer,
        T value,
        [SuppressMessage("ReSharper", "UnusedParameter.Local")]
        JsonSerializerOptions options
    )
    {
        var enumValue = ToFirstEnumName(value);

        writer.WriteStringValue(enumValue);
    }

    private void WriteAsPropertyNameAsFirstEnumName(
        Utf8JsonWriter writer,
        T value,
        [SuppressMessage("ReSharper", "UnusedParameter.Local")]
        JsonSerializerOptions options
    )
    {
        var enumValue = ToFirstEnumName(value);

        writer.WritePropertyName(enumValue);
    }
}

// ReSharper disable once RedundantNullableDirective

#nullable enable

using Aviationexam.GeneratedJsonConverters.Attributes;

namespace Aviationexam.GeneratedJsonConverters;

[DisableEnumJsonConverter]
internal enum EnumSerializationStrategy : byte
{
    ProjectDefault,
    BackingType,
    FirstEnumName,
}

// ReSharper disable once RedundantNullableDirective

#nullable enable

namespace Aviationexam.GeneratedJsonConverters;

internal readonly struct DiscriminatorStruct<t> : IDiscriminatorStruct
{
    public T Value { get; init; }

    public DiscriminatorStruct(T value)
    {
        Value = value;
    }
}

// ReSharper disable once RedundantNullableDirective

#nullable enable

namespace Aviationexam.GeneratedJsonConverters;

internal interface IDiscriminatorStruct
{
}

#nullable enable

namespace Aviationexam.GeneratedJsonConverters.Attributes;

/// <summary>
/// This is a copy of System.Text.Json.Serialization.JsonDerivedTypeAttribute.
/// It's purpose is to replace this attribute to silence System.Text.Json.Serialization.Metadata.PolymorphicTypeResolver{ThrowHelper.ThrowNotSupportedException_BaseConverterDoesNotSupportMetadata}
///
/// When placed on a type declaration, indicates that the specified subtype should be opted into polymorphic serialization.
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
internal class JsonDerivedTypeAttribute : System.Text.Json.Serialization.JsonAttribute
{
    /// <summary>
    /// Initializes a new attribute with specified parameters.
    /// </summary>
    /// <param name="derivedType">A derived type that should be supported in polymorphic serialization of the declared based type.
    public JsonDerivedTypeAttribute(System.Type derivedType)
    {
        DerivedType = derivedType;
    }

    /// <summary>
    /// Initializes a new attribute with specified parameters.
    /// </summary>
    /// <param name="derivedType">A derived type that should be supported in polymorphic serialization of the declared base type.
    /// <param name="typeDiscriminator">The type discriminator identifier to be used for the serialization of the subtype.
    public JsonDerivedTypeAttribute(System.Type derivedType, string typeDiscriminator)
    {
        DerivedType = derivedType;
        TypeDiscriminator = typeDiscriminator;
    }

    /// <summary>
    /// Initializes a new attribute with specified parameters.
    /// </summary>
    /// <param name="derivedType">A derived type that should be supported in polymorphic serialization of the declared base type.
    /// <param name="typeDiscriminator">The type discriminator identifier to be used for the serialization of the subtype.
    public JsonDerivedTypeAttribute(System.Type derivedType, int typeDiscriminator)
    {
        DerivedType = derivedType;
        TypeDiscriminator = typeDiscriminator;
    }

    /// <summary>
    /// A derived type that should be supported in polymorphic serialization of the declared base type.
    /// </summary>
    public System.Type DerivedType { get; }

    /// <summary>
    /// The type discriminator identifier to be used for the serialization of the subtype.
    /// </summary>
    public object? TypeDiscriminator { get; }
}

[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Interface, AllowMultiple = true, Inherited = false)]
internal class JsonDerivedTypeAttribute<tderivedtype> : JsonDerivedTypeAttribute
{
    /// <summary>
    /// Initializes a new attribute with specified parameters.
    /// </summary>
    public JsonDerivedTypeAttribute() : base(typeof(TDerivedType))
    {
    }

    /// <summary>
    /// Initializes a new attribute with specified parameters.
    /// </summary>
    /// <param name="typeDiscriminator">The type discriminator identifier to be used for the serialization of the subtype.
    public JsonDerivedTypeAttribute(string typeDiscriminator) : base(typeof(TDerivedType), typeDiscriminator)
    {
    }

    /// <summary>
    /// Initializes a new attribute with specified parameters.
    /// </summary>
    /// <param name="typeDiscriminator">The type discriminator identifier to be used for the serialization of the subtype.
    public JsonDerivedTypeAttribute(int typeDiscriminator) : base(typeof(TDerivedType), typeDiscriminator)
    {
    }
}
#nullable enable

namespace Aviationexam.GeneratedJsonConverters.Attributes;

/// <summary>
/// This is a copy of System.Text.Json.Serialization.JsonPolymorphicAttribute.
/// It's purpose is to replace this attribute to silence System.Text.Json.Serialization.Metadata.PolymorphicTypeResolver{ThrowHelper.ThrowNotSupportedException_BaseConverterDoesNotSupportMetadata}
///
/// When placed on a type, indicates that the type should be serialized polymorphically.
/// </summary>
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Interface, AllowMultiple = false, Inherited = false)]
internal sealed class JsonPolymorphicAttribute : System.Text.Json.Serialization.JsonAttribute
{
    /// <summary>
    /// Gets or sets a custom type discriminator property name for the polymorhic type.
    /// Uses the default '$type' property name if left unset.
    /// </summary>
    public string? TypeDiscriminatorPropertyName { get; set; }

    /// <summary>
    /// Gets or sets the behavior when serializing an undeclared derived runtime type.
    /// </summary>
    public System.Text.Json.Serialization.JsonUnknownDerivedTypeHandling UnknownDerivedTypeHandling { get; set; }

    /// <summary>
    /// When set to <see langword="true">, instructs the deserializer to ignore any
    /// unrecognized type discriminator id's and reverts to the contract of the base type.
    /// Otherwise, it will fail the deserialization.
    /// </see></summary>
    public bool IgnoreUnrecognizedTypeDiscriminators { get; set; }
}
#nullable enable

namespace PolymorphicGlobalNamespace;

internal class PersonJsonPolymorphicConverter : Aviationexam.GeneratedJsonConverters.PolymorphicJsonConvertor<global::jsonpolymorphicgeneratordemo.person>
{
    protected override System.ReadOnlySpan<byte> GetDiscriminatorPropertyName() =&gt; "$type"u8;

    protected override System.Type GetTypeForDiscriminator(
        Aviationexam.GeneratedJsonConverters.IDiscriminatorStruct discriminator
    ) =&gt; discriminator switch
    {
        Aviationexam.GeneratedJsonConverters.DiscriminatorStruct<string> { Value: "Student" } =&gt; typeof(JsonPolymorphicGeneratorDemo.Student),
        Aviationexam.GeneratedJsonConverters.DiscriminatorStruct<string> { Value: "Teacher" } =&gt; typeof(JsonPolymorphicGeneratorDemo.Teacher),

        _ =&gt; throw new System.ArgumentOutOfRangeException(nameof(discriminator), discriminator, null),
    };

    protected override Aviationexam.GeneratedJsonConverters.IDiscriminatorStruct GetDiscriminatorForType(
        System.Type type
    )
    {
        if (type == typeof(JsonPolymorphicGeneratorDemo.Student))
        {
            return new Aviationexam.GeneratedJsonConverters.DiscriminatorStruct<string>("Student");
        }
        if (type == typeof(JsonPolymorphicGeneratorDemo.Teacher))
        {
            return new Aviationexam.GeneratedJsonConverters.DiscriminatorStruct<string>("Teacher");
        }

        throw new System.ArgumentOutOfRangeException(nameof(type), type, null);
    }
}
// ReSharper disable once RedundantNullableDirective

#nullable enable

using System;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Aviationexam.GeneratedJsonConverters;

internal abstract class PolymorphicJsonConvertor<t> : JsonConverter<t> where T : class
{
    private readonly Type _polymorphicType = typeof(T);

    protected abstract ReadOnlySpan<byte> GetDiscriminatorPropertyName();

    protected abstract Type GetTypeForDiscriminator(IDiscriminatorStruct discriminator);

    protected abstract IDiscriminatorStruct GetDiscriminatorForType(Type type);

    public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var jsonDocument = JsonDocument.ParseValue(ref reader);

        var discriminatorPropertyName = GetDiscriminatorPropertyName();

        var discriminatorProperty = jsonDocument.RootElement
            .GetProperty(discriminatorPropertyName);

        IDiscriminatorStruct? typeDiscriminator = null;
        if (discriminatorProperty.ValueKind is JsonValueKind.String)
        {
            typeDiscriminator = new DiscriminatorStruct<string>(discriminatorProperty.GetString()!);
        }
        else if (discriminatorProperty.ValueKind is JsonValueKind.Number)
        {
            typeDiscriminator = new DiscriminatorStruct<int>(discriminatorProperty.GetInt32());
        }

        if (typeDiscriminator is null)
        {
            var discriminatorPropertyNameString = Encoding.UTF8.GetString(discriminatorPropertyName.ToArray());

            throw new JsonException($"Not found discriminator property '{discriminatorPropertyNameString}' for type {_polymorphicType}");
        }

        var type = GetTypeForDiscriminator(typeDiscriminator);

        return (T?) jsonDocument.Deserialize(type, options);
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        var instanceType = value.GetType();

        writer.WriteStartObject();

        var discriminatorPropertyName = GetDiscriminatorPropertyName();
        var discriminatorValue = GetDiscriminatorForType(instanceType);

        if (discriminatorValue is DiscriminatorStruct<string> discriminatorString)
        {
            writer.WriteString(discriminatorPropertyName, discriminatorString.Value);
        }
        else if (discriminatorValue is DiscriminatorStruct<int> discriminatorInt)
        {
            writer.WriteNumber(discriminatorPropertyName, discriminatorInt.Value);
        }

        var typeInfo = options.GetTypeInfo(instanceType);

        foreach (var p in typeInfo.Properties)
        {
            if (p.Get is null)
            {
                continue;
            }

            writer.WritePropertyName(p.Name);
            JsonSerializer.Serialize(writer, p.Get(value), p.PropertyType, options);
        }

        writer.WriteEndObject();
    }
}

#nullable enable

public partial class ProjectJsonSerializerContext
{
    public static System.Collections.Generic.IReadOnlyCollection<system.text.json.serialization.jsonconverter> GetPolymorphicConverters() =&gt; new System.Text.Json.Serialization.JsonConverter[]
    {
        new PolymorphicGlobalNamespace.PersonJsonPolymorphicConverter(),
    };

    public static void UsePolymorphicConverters(
        System.Collections.Generic.ICollection<system.text.json.serialization.jsonconverter> optionsConverters
    )
    {
        foreach (var converter in GetPolymorphicConverters())
        {
            optionsConverters.Add(converter);
        }
    }
}
// <auto-generated>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
    
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.Json.SourceGeneration", "7.0.9.1816")]
    public partial class ProjectJsonSerializerContext
    {
        
        private static global::System.Text.Json.JsonSerializerOptions s_defaultOptions { get; } = new global::System.Text.Json.JsonSerializerOptions()
        {
            DefaultIgnoreCondition = global::System.Text.Json.Serialization.JsonIgnoreCondition.Never,
            IgnoreReadOnlyFields = false,
            IgnoreReadOnlyProperties = false,
            IncludeFields = false,
            WriteIndented = true,
                    PropertyNamingPolicy = global::System.Text.Json.JsonNamingPolicy.CamelCase
        };
        
        private static global::ProjectJsonSerializerContext? s_defaultContext;
        
        /// <summary>
        /// The default <see cref="global::System.Text.Json.Serialization.JsonSerializerContext"> associated with a default <see cref="global::System.Text.Json.JsonSerializerOptions"> instance.
        /// </see></see></summary>
        public static global::ProjectJsonSerializerContext Default =&gt; s_defaultContext ??= new global::ProjectJsonSerializerContext(new global::System.Text.Json.JsonSerializerOptions(s_defaultOptions));
        
        /// <summary>
        /// The source-generated options associated with this context.
        /// </summary>
        protected override global::System.Text.Json.JsonSerializerOptions? GeneratedSerializerOptions { get; } = s_defaultOptions;
        
        /// <inheritdoc>
        public ProjectJsonSerializerContext() : base(null)
        {
        }
        
        /// <inheritdoc>
        public ProjectJsonSerializerContext(global::System.Text.Json.JsonSerializerOptions options) : base(options)
        {
        }
        
        private static global::System.Text.Json.Serialization.JsonConverter? GetRuntimeProvidedCustomConverter(global::System.Text.Json.JsonSerializerOptions options, global::System.Type type)
        {
            global::System.Collections.Generic.IList<global::system.text.json.serialization.jsonconverter> converters = options.Converters;
        
            for (int i = 0; i &lt; converters.Count; i++)
            {
                global::System.Text.Json.Serialization.JsonConverter? converter = converters[i];
        
                if (converter.CanConvert(type))
                {
                    if (converter is global::System.Text.Json.Serialization.JsonConverterFactory factory)
                    {
                        converter = factory.CreateConverter(type, options);
                        if (converter == null || converter is global::System.Text.Json.Serialization.JsonConverterFactory)
                        {
                            throw new global::System.InvalidOperationException(string.Format("The converter '{0}' cannot return null or a JsonConverterFactory instance.", factory.GetType()));
                        }
                    }
        
                    return converter;
                }
            }
        
            return null;
        }
    }

// <auto-generated>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
    public partial class ProjectJsonSerializerContext: global::System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver
    {
        /// <inheritdoc>
        public override global::System.Text.Json.Serialization.Metadata.JsonTypeInfo GetTypeInfo(global::System.Type type)
        {
            if (type == typeof(global::JsonPolymorphicGeneratorDemo.Person[]))
            {
                return this.PersonArray;
            }
        
            if (type == typeof(global::JsonPolymorphicGeneratorDemo.Person))
            {
                return this.Person;
            }
        
            if (type == typeof(global::System.String))
            {
                return this.String;
            }
        
            if (type == typeof(global::JsonPolymorphicGeneratorDemo.Student))
            {
                return this.Student;
            }
        
            if (type == typeof(global::JsonPolymorphicGeneratorDemo.Teacher))
            {
                return this.Teacher;
            }
        
            return null!;
        }
        
        global::System.Text.Json.Serialization.Metadata.JsonTypeInfo? global::System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver.GetTypeInfo(global::System.Type type, global::System.Text.Json.JsonSerializerOptions options)
        {
            if (type == typeof(global::JsonPolymorphicGeneratorDemo.Person[]))
            {
                return Create_PersonArray(options, makeReadOnly: false);
            }
        
            if (type == typeof(global::JsonPolymorphicGeneratorDemo.Person))
            {
                return Create_Person(options, makeReadOnly: false);
            }
        
            if (type == typeof(global::System.String))
            {
                return Create_String(options, makeReadOnly: false);
            }
        
            if (type == typeof(global::JsonPolymorphicGeneratorDemo.Student))
            {
                return Create_Student(options, makeReadOnly: false);
            }
        
            if (type == typeof(global::JsonPolymorphicGeneratorDemo.Teacher))
            {
                return Create_Teacher(options, makeReadOnly: false);
            }
        
            return null;
        }
        
    }

// <auto-generated>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
    public partial class ProjectJsonSerializerContext
    {
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.person>? _Person;
        /// <summary>
        /// Defines the source generated JSON serialization contract metadata for a given type.
        /// </summary>
        public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.person> Person
        {
            get =&gt; _Person ??= Create_Person(Options, makeReadOnly: true);
        }
        
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.person> Create_Person(global::System.Text.Json.JsonSerializerOptions options, bool makeReadOnly)
        {
            global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.person>? jsonTypeInfo = null;
            global::System.Text.Json.Serialization.JsonConverter? customConverter;
            if (options.Converters.Count &gt; 0 &amp;&amp; (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::JsonPolymorphicGeneratorDemo.Person))) != null)
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::jsonpolymorphicgeneratordemo.person>(options, customConverter);
            }
            else
            {
                global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::jsonpolymorphicgeneratordemo.person> objectInfo = new global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::jsonpolymorphicgeneratordemo.person>()
                {
                    ObjectCreator = null,
                    ObjectWithParameterizedConstructorCreator = null,
                    PropertyMetadataInitializer = _ =&gt; PersonPropInit(options),
                    ConstructorParameterMetadataInitializer = null,
                    NumberHandling = default,
                    SerializeHandler = PersonSerializeHandler
                };
        
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateObjectInfo<global::jsonpolymorphicgeneratordemo.person>(options, objectInfo);
            }
        
            if (makeReadOnly)
            {
                jsonTypeInfo.MakeReadOnly();
            }
        
            return jsonTypeInfo;
        }
        
        private static global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] PersonPropInit(global::System.Text.Json.JsonSerializerOptions options)
        {
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] properties = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[1];
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::system.string> info0 = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::system.string>()
            {
                IsProperty = true,
                IsPublic = true,
                IsVirtual = false,
                DeclaringType = typeof(global::JsonPolymorphicGeneratorDemo.Person),
                Converter = null,
                Getter = static (obj) =&gt; ((global::JsonPolymorphicGeneratorDemo.Person)obj).Name!,
                Setter = static (obj, value) =&gt; ((global::JsonPolymorphicGeneratorDemo.Person)obj).Name = value!,
                IgnoreCondition = null,
                HasJsonInclude = false,
                IsExtensionData = false,
                NumberHandling = default,
                PropertyName = "Name",
                JsonPropertyName = null
            };
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo propertyInfo0 = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreatePropertyInfo<global::system.string>(options, info0);
            properties[0] = propertyInfo0;
        
            return properties;
        }
        
        // Intentionally not a static method because we create a delegate to it. Invoking delegates to instance
        // methods is almost as fast as virtual calls. Static methods need to go through a shuffle thunk.
        private void PersonSerializeHandler(global::System.Text.Json.Utf8JsonWriter writer, global::JsonPolymorphicGeneratorDemo.Person? value)
        {
            if (value == null)
            {
                writer.WriteNullValue();
                return;
            }
        
            writer.WriteStartObject();
            writer.WriteString(PropName_name, value.Name);
        
            writer.WriteEndObject();
        }
    }

// <auto-generated>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
    public partial class ProjectJsonSerializerContext
    {
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.person  &#91;&#93;>? _PersonArray;
        /// <summary>
        /// Defines the source generated JSON serialization contract metadata for a given type.
        /// </summary>
        public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.person  &#91;&#93;> PersonArray
        {
            get =&gt; _PersonArray ??= Create_PersonArray(Options, makeReadOnly: true);
        }
        
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.person  &#91;&#93;> Create_PersonArray(global::System.Text.Json.JsonSerializerOptions options, bool makeReadOnly)
        {
            global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.person  &#91;&#93;>? jsonTypeInfo = null;
            global::System.Text.Json.Serialization.JsonConverter? customConverter;
            if (options.Converters.Count &gt; 0 &amp;&amp; (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::JsonPolymorphicGeneratorDemo.Person[]))) != null)
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::jsonpolymorphicgeneratordemo.person  &#91;&#93;>(options, customConverter);
            }
            else
            {
                global::System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<global::jsonpolymorphicgeneratordemo.person  &#91;&#93;> info = new global::System.Text.Json.Serialization.Metadata.JsonCollectionInfoValues<global::jsonpolymorphicgeneratordemo.person  &#91;&#93;>()
                {
                    ObjectCreator = null,
                    NumberHandling = default,
                    SerializeHandler = PersonArraySerializeHandler
                };
        
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateArrayInfo<global::jsonpolymorphicgeneratordemo.person>(options, info);
        
            }
        
            if (makeReadOnly)
            {
                jsonTypeInfo.MakeReadOnly();
            }
        
            return jsonTypeInfo;
        }
        
        
        // Intentionally not a static method because we create a delegate to it. Invoking delegates to instance
        // methods is almost as fast as virtual calls. Static methods need to go through a shuffle thunk.
        private void PersonArraySerializeHandler(global::System.Text.Json.Utf8JsonWriter writer, global::JsonPolymorphicGeneratorDemo.Person[]? value)
        {
            if (value == null)
            {
                writer.WriteNullValue();
                return;
            }
        
            writer.WriteStartArray();
        
            for (int i = 0; i &lt; value.Length; i++)
            {
                PersonSerializeHandler(writer, value[i]!);
            }
        
            writer.WriteEndArray();
        }
    }

// <auto-generated>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
    public partial class ProjectJsonSerializerContext
    {
        
        private static readonly global::System.Text.Json.JsonEncodedText PropName_name = global::System.Text.Json.JsonEncodedText.Encode("name");
    }

// <auto-generated>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
    public partial class ProjectJsonSerializerContext
    {
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::system.string>? _String;
        /// <summary>
        /// Defines the source generated JSON serialization contract metadata for a given type.
        /// </summary>
        public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::system.string> String
        {
            get =&gt; _String ??= Create_String(Options, makeReadOnly: true);
        }
        
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::system.string> Create_String(global::System.Text.Json.JsonSerializerOptions options, bool makeReadOnly)
        {
            global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::system.string>? jsonTypeInfo = null;
            global::System.Text.Json.Serialization.JsonConverter? customConverter;
            if (options.Converters.Count &gt; 0 &amp;&amp; (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::System.String))) != null)
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::system.string>(options, customConverter);
            }
            else
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::system.string>(options, global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.StringConverter);
            }
        
            if (makeReadOnly)
            {
                jsonTypeInfo.MakeReadOnly();
            }
        
            return jsonTypeInfo;
        }
        
    }

// <auto-generated>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
    public partial class ProjectJsonSerializerContext
    {
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.student>? _Student;
        /// <summary>
        /// Defines the source generated JSON serialization contract metadata for a given type.
        /// </summary>
        public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.student> Student
        {
            get =&gt; _Student ??= Create_Student(Options, makeReadOnly: true);
        }
        
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.student> Create_Student(global::System.Text.Json.JsonSerializerOptions options, bool makeReadOnly)
        {
            global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.student>? jsonTypeInfo = null;
            global::System.Text.Json.Serialization.JsonConverter? customConverter;
            if (options.Converters.Count &gt; 0 &amp;&amp; (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::JsonPolymorphicGeneratorDemo.Student))) != null)
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::jsonpolymorphicgeneratordemo.student>(options, customConverter);
            }
            else
            {
                global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::jsonpolymorphicgeneratordemo.student> objectInfo = new global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::jsonpolymorphicgeneratordemo.student>()
                {
                    ObjectCreator = static () =&gt; new global::JsonPolymorphicGeneratorDemo.Student(),
                    ObjectWithParameterizedConstructorCreator = null,
                    PropertyMetadataInitializer = _ =&gt; StudentPropInit(options),
                    ConstructorParameterMetadataInitializer = null,
                    NumberHandling = default,
                    SerializeHandler = StudentSerializeHandler
                };
        
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateObjectInfo<global::jsonpolymorphicgeneratordemo.student>(options, objectInfo);
            }
        
            if (makeReadOnly)
            {
                jsonTypeInfo.MakeReadOnly();
            }
        
            return jsonTypeInfo;
        }
        
        private static global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] StudentPropInit(global::System.Text.Json.JsonSerializerOptions options)
        {
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] properties = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[1];
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::system.string> info0 = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::system.string>()
            {
                IsProperty = true,
                IsPublic = true,
                IsVirtual = false,
                DeclaringType = typeof(global::JsonPolymorphicGeneratorDemo.Person),
                Converter = null,
                Getter = static (obj) =&gt; ((global::JsonPolymorphicGeneratorDemo.Person)obj).Name!,
                Setter = static (obj, value) =&gt; ((global::JsonPolymorphicGeneratorDemo.Person)obj).Name = value!,
                IgnoreCondition = null,
                HasJsonInclude = false,
                IsExtensionData = false,
                NumberHandling = default,
                PropertyName = "Name",
                JsonPropertyName = null
            };
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo propertyInfo0 = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreatePropertyInfo<global::system.string>(options, info0);
            properties[0] = propertyInfo0;
        
            return properties;
        }
        
        // Intentionally not a static method because we create a delegate to it. Invoking delegates to instance
        // methods is almost as fast as virtual calls. Static methods need to go through a shuffle thunk.
        private void StudentSerializeHandler(global::System.Text.Json.Utf8JsonWriter writer, global::JsonPolymorphicGeneratorDemo.Student? value)
        {
            if (value == null)
            {
                writer.WriteNullValue();
                return;
            }
        
            writer.WriteStartObject();
            writer.WriteString(PropName_name, value.Name);
        
            writer.WriteEndObject();
        }
    }

// <auto-generated>

#nullable enable annotations
#nullable disable warnings

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618
    public partial class ProjectJsonSerializerContext
    {
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.teacher>? _Teacher;
        /// <summary>
        /// Defines the source generated JSON serialization contract metadata for a given type.
        /// </summary>
        public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.teacher> Teacher
        {
            get =&gt; _Teacher ??= Create_Teacher(Options, makeReadOnly: true);
        }
        
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.teacher> Create_Teacher(global::System.Text.Json.JsonSerializerOptions options, bool makeReadOnly)
        {
            global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::jsonpolymorphicgeneratordemo.teacher>? jsonTypeInfo = null;
            global::System.Text.Json.Serialization.JsonConverter? customConverter;
            if (options.Converters.Count &gt; 0 &amp;&amp; (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::JsonPolymorphicGeneratorDemo.Teacher))) != null)
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::jsonpolymorphicgeneratordemo.teacher>(options, customConverter);
            }
            else
            {
                global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::jsonpolymorphicgeneratordemo.teacher> objectInfo = new global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::jsonpolymorphicgeneratordemo.teacher>()
                {
                    ObjectCreator = static () =&gt; new global::JsonPolymorphicGeneratorDemo.Teacher(),
                    ObjectWithParameterizedConstructorCreator = null,
                    PropertyMetadataInitializer = _ =&gt; TeacherPropInit(options),
                    ConstructorParameterMetadataInitializer = null,
                    NumberHandling = default,
                    SerializeHandler = TeacherSerializeHandler
                };
        
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateObjectInfo<global::jsonpolymorphicgeneratordemo.teacher>(options, objectInfo);
            }
        
            if (makeReadOnly)
            {
                jsonTypeInfo.MakeReadOnly();
            }
        
            return jsonTypeInfo;
        }
        
        private static global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] TeacherPropInit(global::System.Text.Json.JsonSerializerOptions options)
        {
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] properties = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[1];
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::system.string> info0 = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::system.string>()
            {
                IsProperty = true,
                IsPublic = true,
                IsVirtual = false,
                DeclaringType = typeof(global::JsonPolymorphicGeneratorDemo.Person),
                Converter = null,
                Getter = static (obj) =&gt; ((global::JsonPolymorphicGeneratorDemo.Person)obj).Name!,
                Setter = static (obj, value) =&gt; ((global::JsonPolymorphicGeneratorDemo.Person)obj).Name = value!,
                IgnoreCondition = null,
                HasJsonInclude = false,
                IsExtensionData = false,
                NumberHandling = default,
                PropertyName = "Name",
                JsonPropertyName = null
            };
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo propertyInfo0 = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreatePropertyInfo<global::system.string>(options, info0);
            properties[0] = propertyInfo0;
        
            return properties;
        }
        
        // Intentionally not a static method because we create a delegate to it. Invoking delegates to instance
        // methods is almost as fast as virtual calls. Static methods need to go through a shuffle thunk.
        private void TeacherSerializeHandler(global::System.Text.Json.Utf8JsonWriter writer, global::JsonPolymorphicGeneratorDemo.Teacher? value)
        {
            if (value == null)
            {
                writer.WriteNullValue();
                return;
            }
        
            writer.WriteStartObject();
            writer.WriteString(PropName_name, value.Name);
        
            writer.WriteEndObject();
        }
    }

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/jsonConverterSourceGenerator

Adding more data to a result of a task

Every now and then I need to generate , from an array of data, an array of Tasks and then

await Task.WhenAll(TheTaskArray)

The problem is that I need to consolidate the return data of each array with the original array – to make some modifications.

For  example, in the generator of https://ignatandrei.github.io/RSCG_Examples/v2/docs/category/rscg-examples I do something like this

var t = _AllDescriptions
            .Select(it =>GrabReadMe(it))
            .ToArray();
var data = await Task.WhenAll(t);
//now, for each item in data array I want to put something into original _AllDescriptions

My first try was a simple class

public struct TaskWithData<TData, TResult>//: INotifyCompletion
{
    private readonly TData data;
    private readonly Task<TResult> taskToExecute;
 
    public TaskWithData(TData data,Task<TResult> taskToExecute)
    {
        ArgumentNullException.ThrowIfNull(taskToExecute);
        this.data = data;
        this.taskToExecute = taskToExecute;
    }
# region add this to have Task.WhenAll
    public async Task<( TData data, TResult res)> GetTask() {
        var res = await taskToExecute;
        return (data,res);
    }
    public static explicit operator Task<(TData data, TResult res)>(TaskWithData<TData,TResult> b) 
        => b.GetTask() ;

    #endregion
}

And now the code could be written as

var t = _AllDescriptions.Select(
            it => new TaskWithData<Description, string?>(it, GrabReadMe(it))
            )
            .Select(td=>td.GetTask())            
            .ToArray();

        var desc = await Task.WhenAll(t);
        foreach (var item in desc)
        {
            item.data.Readme = item.res;
        }

But I do not like so much … so 2 iterations with extensions

public static class Extensions
{ 
    #region transform to task
    public static Task<( TData data, TResult res)> AddData<TData, TResult>(this Task<TResult> taskToExecute, TData data)
    {
        var td=new TaskWithData<TData, TResult>(data,taskToExecute);
        return td.GetTask();
    }
    public static Task<(TData data, TResult res)>[] SelectTaskWithData<TData, TResult>(this TData[] arr,Func<TData, Task<TResult>> func) {
        return arr.Select(it => func(it).AddData(it)).ToArray();
    }
    #endregion
}

So now the code becomes

var t = _AllDescriptions
            .Select(it =>GrabReadMe(it).AddData(it))
            .ToArray();

or

var t = _AllDescriptions.SelectTaskWithData(GrabReadMe).ToArray();

It was interesting to create this in order to add more data to the return value of a Task

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

RSCG – ApparatusAOT

RSCG – ApparatusAOT
 
 

name ApparatusAOT
nuget https://www.nuget.org/packages/Apparatus.AOT.Reflection/
link https://github.com/byme8/Apparatus.AOT.Reflection
author Stanislav Silin

This will generate code for investigating at runtime the properties of an object

 

This is how you can use ApparatusAOT .

The code that you start with is


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

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net7.0</TargetFramework>
	</PropertyGroup>

	<ItemGroup>
		<PackageReference Include="Apparatus.AOT.Reflection" Version="0.2.0" />
	</ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

</Project>


The code that you will use is


using Apparatus.AOT.Reflection;
using ApparatusDemo;
using System;

Person p1 = new();
p1.FirstName = "Andrei1";
p1.LastName = "Ignat1";

Person p2 = new ();
p2.FirstName = "Andrei2";
p2.LastName = "Ignat2";

var prop =p1.GetProperties().Values;
foreach (var item in prop)
{
    Console.WriteLine($"{item.Name} Attr: {item.Attributes.Length} value {item.Name}");
    if (item.TryGetValue(p1, out var val))
    {
        Console.WriteLine("value : " + val);
    }

}
foreach (var item in prop)
{
    Console.WriteLine($"{item.Name} Attr: {item.Attributes.Length} value {item.Name}");
    if (item.TryGetValue(p2, out var val))
    {
        Console.WriteLine("value : " + val);
    }

}



using System.ComponentModel.DataAnnotations;
namespace ApparatusDemo;
class Person
{
    [Required]
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

 

The code that is generated is


using System;
using System.Linq;

namespace Apparatus.AOT.Reflection
{
    public static class ApparatusDemo_PersonExtensions
    {
        [global::System.Runtime.CompilerServices.ModuleInitializer]
        public static void Bootstrap()
        {
            MetadataStore<global::ApparatusDemo.Person>.Data = _lazy;
        }

        private static global::System.Lazy<global::System.Collections.Generic.IReadOnlyDictionary<string, IPropertyInfo>> _lazy = new global::System.Lazy<global::System.Collections.Generic.IReadOnlyDictionary<string, IPropertyInfo>>(new global::System.Collections.Generic.Dictionary<string, IPropertyInfo>
        {
            { "FirstName", new global::Apparatus.AOT.Reflection.PropertyInfo<global::ApparatusDemo.Person,string>(
                        "FirstName", 
                        new global::System.Attribute[] 
                        {
                            new global::System.ComponentModel.DataAnnotations.RequiredAttribute(),
                        }, 
                        instance => instance.FirstName, (instance, value) => instance.FirstName = value)
                },
            { "LastName", new global::Apparatus.AOT.Reflection.PropertyInfo<global::ApparatusDemo.Person,string>(
                        "LastName", 
                        new global::System.Attribute[] 
                        {
                            
                        }, 
                        instance => instance.LastName, (instance, value) => instance.LastName = value)
                },
        }); 


        internal static global::System.Collections.Generic.IReadOnlyDictionary<string, IPropertyInfo> GetProperties(this global::ApparatusDemo.Person value)
        {
            return _lazy.Value;
        }   
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/ApparatusAOT

RSCG – PartiallyApplied

RSCG – PartiallyApplied
 
 

name PartiallyApplied
nuget https://www.nuget.org/packages/PartiallyApplied/
link https://github.com/JasonBock/PartiallyApplied/blob/main/docs/Quickstart.md
author Jason Bock

If you need to curry functions, you can use this package

 

This is how you can use PartiallyApplied .

The code that you start with is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
  </PropertyGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

	<ItemGroup>
    <PackageReference Include="PartiallyApplied" Version="1.3.0" />
  </ItemGroup>

</Project>


The code that you will use is


using System;

namespace PartFunc;
class Program
{
    static void Main(string[] args)
    {
        
        var disc10Percent = Partially.Apply(Accounting.Discount, 1/10f);
        Console.WriteLine(disc10Percent(disc10Percent(100)));
        
    }
}



namespace PartFunc;

public class Accounting
{
    public static float Discount( float discount, float price)
    {
        var val= price * (1- discount);
        return val;
    }
}


 

The code that is generated is

using System;

#nullable enable
public static partial class Partially
{
	public static Func<float, float> Apply(Func<float, float, float> method, float discount) =>
		new((price) => method(discount, price));
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/PartiallyApplied

RSCG – RazorBlade

RSCG – RazorBlade
 
 

name RazorBlade
nuget https://www.nuget.org/packages/RazorBlade/
link https://github.com/ltrzesniewski/RazorBlade
author Lucas Trzesniewski

Fast templating with Razor syntax

Do not forget to put into AdditionalFiles section of csproj file

 

This is how you can use RazorBlade .

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="RazorBlade" Version="0.4.3" PrivateAssets="all" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
	</ItemGroup>
	<ItemGroup>
		<AdditionalFiles Include="PersonDisplay.cshtml" />
	</ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using RazorBladeDemo;

Console.WriteLine("Hello, World!");
Person p = new();
p.FirstName= "Andrei";
p.LastName = "Ignat";


var template = new PersonDisplay(p);
var result = template.Render();
Console.WriteLine(result);



namespace RazorBladeDemo;

public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public string FullName()
    {
        return FirstName + " "+LastName;
    }
}



@using RazorBladeDemo;
@inherits RazorBlade.HtmlTemplate<Person>;

This is the @Model.FirstName @Model.LastName

<br />

This should be full name of @Model.FullName()

 

The code that is generated is

// This file is part of the RazorBlade library.

#nullable enable

using System;

namespace RazorBlade.Support;

/// <summary>
/// Specifies that this constructor needs to be provided by the generated template class.
/// </summary>
[AttributeUsage(AttributeTargets.Constructor)]
internal sealed class TemplateConstructorAttribute : Attribute
{
}

/// <summary>
/// Specifies if a method should be used depending on the template being sync or async.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
internal sealed class ConditionalOnAsyncAttribute : Attribute
{
    /// <summary>
    /// The message to display.
    /// </summary>
    public string? Message { get; set; }

    /// <summary>
    /// Marks a method as meant to be used in a sync or async template.
    /// </summary>
    /// <param name="async">True for methods meant to be used in async templates, and false for methods meant to be used for sync templates.</param>
    public ConditionalOnAsyncAttribute(bool async)
    {
    }
}

// This file is part of the RazorBlade library.

#nullable enable

using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;

namespace RazorBlade;

// ReSharper disable once RedundantDisableWarningComment
#pragma warning disable CA1822

/// <summary>
/// Utilities for HTML Razor templates.
/// </summary>
[SuppressMessage("ReSharper", "MemberCanBeMadeStatic.Global")]
internal sealed class HtmlHelper
{
    internal static HtmlHelper Instance { get; } = new();

    /// <summary>
    /// Returns markup that is not HTML encoded.
    /// </summary>
    /// <param name="value">The HTML markup.</param>
    public HtmlString Raw(object? value)
        => new(value?.ToString());

    /// <summary>
    /// HTML-encodes the provided value.
    /// </summary>
    /// <param name="value">Value to HTML-encode.</param>
    public string Encode(object? value)
    {
        var valueString = value?.ToString();
        if (valueString is null or "")
            return string.Empty;

#if NET6_0_OR_GREATER
        var valueSpan = valueString.AsSpan();
        var sb = new StringBuilder();

        while (true)
        {
            var idx = valueSpan.IndexOfAny("&<>\"\'");
            if (idx < 0)
                break;

            if (idx != 0)
                sb.Append(valueSpan[..idx]);

            sb.Append(valueSpan[idx] switch
            {
                '&'   => "&amp;",
                '<'   => "&lt;",
                '>'   => "&gt;",
                '"'   => "&quot;",
                '\''  => "&#x27;",
                var c => c.ToString() // Won't happen
            });

            valueSpan = valueSpan[(idx + 1)..];
        }

        if (valueSpan.Length != 0)
            sb.Append(valueSpan);

        return sb.ToString();
#else
        return valueString.Replace("&", "&amp;")
                          .Replace("<", "&lt;")
                          .Replace(">", "&gt;")
                          .Replace("\"", "&quot;")
                          .Replace("\'", "&#x27;");
#endif
    }
}

// This file is part of the RazorBlade library.

#nullable enable

using System.IO;

namespace RazorBlade;

/// <summary>
/// Represents an HTML-encoded string that should not be encoded again.
/// </summary>
internal sealed class HtmlString : IEncodedContent
{
    private readonly string _value;

    /// <summary>
    /// Creates a HTML-encoded string.
    /// </summary>
    public HtmlString(string? value)
        => _value = value ?? string.Empty;

    /// <inheritdoc />
    public override string ToString()
        => _value;

    void IEncodedContent.WriteTo(TextWriter textWriter)
        => textWriter.Write(_value);
}

// This file is part of the RazorBlade library.

#nullable enable

using System;
using System.Diagnostics.CodeAnalysis;
using RazorBlade.Support;

namespace RazorBlade;

/// <summary>
/// Base class for HTML templates.
/// </summary>
/// <remarks>
/// Special HTML characters will be escaped.
/// </remarks>
internal abstract class HtmlTemplate : RazorTemplate
{
    private AttributeInfo _currentAttribute;

    // ReSharper disable once RedundantDisableWarningComment
#pragma warning disable CA1822

    /// <inheritdoc cref="HtmlHelper"/>
    [SuppressMessage("ReSharper", "MemberCanBeMadeStatic.Global")]
    protected HtmlHelper Html => HtmlHelper.Instance;

    /// <inheritdoc cref="HtmlHelper.Raw"/>
    [SuppressMessage("ReSharper", "MemberCanBeMadeStatic.Global")]
    protected HtmlString Raw(object? value)
        => HtmlHelper.Instance.Raw(value);

#pragma warning restore CA1822

    /// <inheritdoc />
    protected override void Write(object? value)
    {
        if (value is IEncodedContent encodedContent)
        {
            encodedContent.WriteTo(Output);
            return;
        }

        var valueString = value?.ToString();
        if (valueString is null or "")
            return;

#if NET6_0_OR_GREATER
        var valueSpan = valueString.AsSpan();

        while (true)
        {
            var idx = valueSpan.IndexOfAny("&<>\"\'");
            if (idx < 0)
                break;

            if (idx != 0)
                Output.Write(valueSpan[..idx]);

            Output.Write(valueSpan[idx] switch
            {
                '&'   => "&amp;",
                '<'   => "&lt;",
                '>'   => "&gt;",
                '"'   => "&quot;",
                '\''  => "&#x27;",
                var c => c.ToString() // Won't happen
            });

            valueSpan = valueSpan[(idx + 1)..];
        }

        if (valueSpan.Length != 0)
            Output.Write(valueSpan);
#else
        Output.Write(
            valueString.Replace("&", "&amp;")
                       .Replace("<", "&lt;")
                       .Replace(">", "&gt;")
                       .Replace("\"", "&quot;")
                       .Replace("\'", "&#x27;")
        );
#endif
    }

    /// <inheritdoc />
    protected override void BeginWriteAttribute(string name, string prefix, int prefixOffset, string suffix, int suffixOffset, int attributeValuesCount)
    {
        _currentAttribute = new(name, prefix, suffix, attributeValuesCount);

        if (_currentAttribute.AttributeValuesCount != 1)
            WriteLiteral(prefix);
    }

    /// <inheritdoc />
    protected override void WriteAttributeValue(string prefix, int prefixOffset, object? value, int valueOffset, int valueLength, bool isLiteral)
    {
        // This implements the Razor semantics of ASP.NET (conditional attributes):

        // When an attribute consists of a single value part (without whitespace): foo="@bar"
        //  - if bar evaluates to false or null, omit the attribute entirely
        //  - if bar evaluates to true, write the attribute name as the value: foo="foo"
        //  - otherwise, write the value of bar as usual

        // When an attribute contains multiple value parts: class="foo @bar"
        //  - if bar evaluates to null, omit it and its whitespace prefix: class="foo"
        //  - otherwise, write the value of bar as usual (even if it evaluates to a boolean)

        // Note that if an attribute name starts with "data-", these attribute-specific methods are not called,
        // and Write is used instead, effectively bypassing these rules and always writing the attribute value as-is.

        if (_currentAttribute.AttributeValuesCount == 1)
        {
            if (string.IsNullOrEmpty(prefix))
            {
                if (value is bool boolValue)
                    value = boolValue ? _currentAttribute.Name : null;

                if (value is null)
                {
                    _currentAttribute.Suppressed = true;
                    return;
                }
            }

            WriteLiteral(_currentAttribute.Prefix);
        }

        if (value is not null)
        {
            WriteLiteral(prefix);

            if (isLiteral)
                WriteLiteral(value.ToString());
            else
                Write(value);
        }
    }

    /// <inheritdoc />
    protected override void EndWriteAttribute()
    {
        if (!_currentAttribute.Suppressed)
            WriteLiteral(_currentAttribute.Suffix);
    }

    private struct AttributeInfo
    {
        public readonly string? Name;
        public readonly string? Prefix;
        public readonly string? Suffix;
        public readonly int AttributeValuesCount;
        public bool Suppressed;

        public AttributeInfo(string name, string prefix, string suffix, int attributeValuesCount)
        {
            Name = name;
            Prefix = prefix;
            Suffix = suffix;
            AttributeValuesCount = attributeValuesCount;

            Suppressed = false;
        }
    }
}

/// <summary>
/// Base class for HTML templates with a model.
/// </summary>
/// <remarks>
/// Special HTML characters will be escaped.
/// </remarks>
/// <typeparam name="TModel">The model type.</typeparam>
internal abstract class HtmlTemplate<TModel> : HtmlTemplate
{
    /// <summary>
    /// The model for the template.
    /// </summary>
    public TModel Model { get; }

    /// <summary>
    /// Initializes a new instance of the template.
    /// </summary>
    /// <param name="model">The model for the template.</param>
    [TemplateConstructor]
    protected HtmlTemplate(TModel model)
    {
        Model = model;
    }

    /// <summary>
    /// This constructor is provided for the designer only. Do not use.
    /// </summary>
    protected HtmlTemplate()
    {
        throw new NotSupportedException("Use the constructor overload that takes a model.");
    }
}

// This file is part of the RazorBlade library.

#nullable enable

using System.IO;

namespace RazorBlade;

/// <summary>
/// Encoded content to we written to the output as-is.
/// </summary>
internal interface IEncodedContent
{
    /// <summary>
    /// Writes the content to the provided <see cref="TextWriter"/>.
    /// </summary>
    /// <param name="textWriter"><see cref="TextWriter"/> to write the content to.</param>
    void WriteTo(TextWriter textWriter);
}

// This file is part of the RazorBlade library.

#nullable enable

using System;
using RazorBlade.Support;

namespace RazorBlade;

/// <summary>
/// Base class for plain text templates.
/// </summary>
/// <remarks>
/// Values will be written as-is, without escaping.
/// </remarks>
internal abstract class PlainTextTemplate : RazorTemplate
{
    private string? _currentAttributeSuffix;

    /// <inheritdoc />
    protected override void Write(object? value)
    {
        if (value is IEncodedContent encodedContent)
            encodedContent.WriteTo(Output);
        else
            Output.Write(value);
    }

    /// <inheritdoc />
    protected override void BeginWriteAttribute(string name, string prefix, int prefixOffset, string suffix, int suffixOffset, int attributeValuesCount)
    {
        WriteLiteral(prefix);
        _currentAttributeSuffix = suffix;
    }

    /// <inheritdoc />
    protected override void WriteAttributeValue(string prefix, int prefixOffset, object? value, int valueOffset, int valueLength, bool isLiteral)
    {
        WriteLiteral(prefix);

        if (isLiteral)
            WriteLiteral(value?.ToString());
        else
            Write(value);
    }

    /// <inheritdoc />
    protected override void EndWriteAttribute()
    {
        WriteLiteral(_currentAttributeSuffix);
        _currentAttributeSuffix = null;
    }
}

/// <summary>
/// Base class for plain text templates with a model.
/// </summary>
/// <remarks>
/// Values will be written as-is, without escaping.
/// </remarks>
/// <typeparam name="TModel">The model type.</typeparam>
internal abstract class PlainTextTemplate<TModel> : PlainTextTemplate
{
    /// <summary>
    /// The model for the template.
    /// </summary>
    public TModel Model { get; }

    /// <summary>
    /// Initializes a new instance of the template.
    /// </summary>
    /// <param name="model">The model for the template.</param>
    [TemplateConstructor]
    protected PlainTextTemplate(TModel model)
    {
        Model = model;
    }

    /// <summary>
    /// This constructor is provided for the designer only. Do not use.
    /// </summary>
    protected PlainTextTemplate()
    {
        throw new NotSupportedException("Use the constructor overload that takes a model.");
    }
}

// This file is part of the RazorBlade library.

#nullable enable

using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using RazorBlade.Support;

namespace RazorBlade;

/// <summary>
/// Base class for Razor templates.
/// </summary>
internal abstract class RazorTemplate : IEncodedContent
{
    /// <summary>
    /// The <see cref="TextWriter"/> which receives the output.
    /// </summary>
    protected TextWriter Output { get; set; } = new StreamWriter(Stream.Null);

    /// <summary>
    /// The cancellation token.
    /// </summary>
    protected CancellationToken CancellationToken { get; private set; }

    /// <summary>
    /// Renders the template synchronously and returns the result as a string.
    /// </summary>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <remarks>
    /// Use this only if the template does not use <c>@async</c> directives.
    /// </remarks>
    [ConditionalOnAsync(false, Message = $"The generated template is async. Use {nameof(RenderAsync)} instead.")]
    public string Render(CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();

        var renderTask = RenderAsync(cancellationToken);
        if (renderTask.IsCompleted)
            return renderTask.Result;

        return Task.Run(async () => await renderTask.ConfigureAwait(false), CancellationToken.None).GetAwaiter().GetResult();
    }

    /// <summary>
    /// Renders the template synchronously to the given <see cref="TextWriter"/>.
    /// </summary>
    /// <param name="textWriter">The <see cref="TextWriter"/> to write to.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <remarks>
    /// Use this only if the template does not use <c>@async</c> directives.
    /// </remarks>
    [ConditionalOnAsync(false, Message = $"The generated template is async. Use {nameof(RenderAsync)} instead.")]
    public void Render(TextWriter textWriter, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();

        var renderTask = RenderAsync(textWriter, cancellationToken);
        if (renderTask.IsCompleted)
        {
            renderTask.GetAwaiter().GetResult();
            return;
        }

        Task.Run(async () => await renderTask.ConfigureAwait(false), CancellationToken.None).GetAwaiter().GetResult();
    }

    /// <summary>
    /// Renders the template asynchronously and returns the result as a string.
    /// </summary>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <remarks>
    /// Use this if the template uses <c>@async</c> directives.
    /// </remarks>
    public async Task<string> RenderAsync(CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();

        var output = new StringWriter();
        await RenderAsync(output, cancellationToken).ConfigureAwait(false);
        return output.ToString();
    }

    /// <summary>
    /// Renders the template asynchronously to the given <see cref="TextWriter"/>.
    /// </summary>
    /// <param name="textWriter">The <see cref="TextWriter"/> to write to.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <remarks>
    /// Use this if the template uses <c>@async</c> directives.
    /// </remarks>
    public async Task RenderAsync(TextWriter textWriter, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();

        var previousState = (Output, CancellationToken);

        try
        {
            Output = textWriter;
            CancellationToken = cancellationToken;

            await ExecuteAsync().ConfigureAwait(false);
        }
        finally
        {
            (Output, CancellationToken) = previousState;
        }
    }

    /// <summary>
    /// Executes the template and appends the result to <see cref="Output"/>.
    /// </summary>
    protected virtual Task ExecuteAsync()
        => Task.CompletedTask; // The IDE complains when this method is abstract :(

    /// <summary>
    /// Writes a literal value to the output.
    /// </summary>
    /// <param name="value">The value to write.</param>
    protected void WriteLiteral(string? value)
        => Output.Write(value);

    /// <summary>
    /// Write a value to the output.
    /// </summary>
    /// <param name="value">The value to write.</param>
    protected abstract void Write(object? value);

    /// <summary>
    /// Write already encoded content to the output.
    /// </summary>
    /// <param name="content">The template to render.</param>
    protected void Write(IEncodedContent? content)
        => content?.WriteTo(Output);

    /// <summary>
    /// Begins writing an attribute.
    /// </summary>
    /// <param name="name">The attribute name.</param>
    /// <param name="prefix">The attribute prefix, which is the text from the whitespace preceding the attribute name to the quote before the attribute value.</param>
    /// <param name="prefixOffset">The prefix offset in the Razor file.</param>
    /// <param name="suffix">The suffix, consisting of the end quote.</param>
    /// <param name="suffixOffset">The suffix offset in the Razor file.</param>
    /// <param name="attributeValuesCount">The count of attribute value parts, which is the count of subsequent <see cref="WriteAttributeValue"/> calls.</param>
    [EditorBrowsable(EditorBrowsableState.Never)]
    protected abstract void BeginWriteAttribute(string name, string prefix, int prefixOffset, string suffix, int suffixOffset, int attributeValuesCount);

    /// <summary>
    /// Writes part of an attribute value.
    /// </summary>
    /// <param name="prefix">The value prefix, consisting of the whitespace preceding the value.</param>
    /// <param name="prefixOffset">The prefix offset in the Razor file.</param>
    /// <param name="value">The value to write.</param>
    /// <param name="valueOffset">The value offset in the Razor file.</param>
    /// <param name="valueLength">The value length in the Razor file.</param>
    /// <param name="isLiteral">Whether the value is a literal.</param>
    [EditorBrowsable(EditorBrowsableState.Never)]
    protected abstract void WriteAttributeValue(string prefix, int prefixOffset, object? value, int valueOffset, int valueLength, bool isLiteral);

    /// <summary>
    /// Ends writing an attribute.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    protected abstract void EndWriteAttribute();

    void IEncodedContent.WriteTo(TextWriter textWriter)
        => Render(textWriter, CancellationToken.None);
}

#pragma checksum "C:\test\RSCG_Examples\v2\rscg_examples\RazorBlade\src\RazorBladeDemo\PersonDisplay.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "0ee9a5bcc623252570e9d97efdeb7e3c5a8d6350"
// <auto-generated/>
#pragma warning disable 1591
namespace RazorBladeDemo
{
    #line hidden
#nullable restore
#line 1 "C:\test\RSCG_Examples\v2\rscg_examples\RazorBlade\src\RazorBladeDemo\PersonDisplay.cshtml"
using RazorBladeDemo;

#line default
#line hidden
#nullable disable
    #nullable restore
    internal partial class PersonDisplay : RazorBlade.HtmlTemplate<Person>
    #nullable disable
    {
        #pragma warning disable 1998
        protected async override global::System.Threading.Tasks.Task ExecuteAsync()
        {
            WriteLiteral("\r\nThis is the ");
#nullable restore
#line (4,14)-(4,29) 6 "C:\test\RSCG_Examples\v2\rscg_examples\RazorBlade\src\RazorBladeDemo\PersonDisplay.cshtml"
Write(Model.FirstName);

#line default
#line hidden
#nullable disable
            WriteLiteral(" ");
#nullable restore
#line (4,31)-(4,45) 6 "C:\test\RSCG_Examples\v2\rscg_examples\RazorBlade\src\RazorBladeDemo\PersonDisplay.cshtml"
Write(Model.LastName);

#line default
#line hidden
#nullable disable
            WriteLiteral("\r\n\r\n<br />\r\n\r\nThis should be full name of ");
#nullable restore
#line (8,30)-(8,46) 6 "C:\test\RSCG_Examples\v2\rscg_examples\RazorBlade\src\RazorBladeDemo\PersonDisplay.cshtml"
Write(Model.FullName());

#line default
#line hidden
#nullable disable
        }
        #pragma warning restore 1998
    }
}
#pragma warning restore 1591

// <auto-generated/>

#nullable restore

namespace RazorBladeDemo
{
    partial class PersonDisplay
    {
        /// <inheritdoc cref="M:RazorBlade.HtmlTemplate`1.#ctor(`0)" />
        public PersonDisplay(global::RazorBladeDemo.Person model)
            : base(model)
        {
        }
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/RazorBlade

RSCG – Vogen

RSCG – Vogen
 
 

name Vogen
nuget https://www.nuget.org/packages/Vogen/
link https://dunnhq.com/posts/2021/primitive-obsession/
author Steve Dunn

Transform values( e.g. int) into classes

If you know what are ValueObject,that is one solution

 

This is how you can use Vogen .

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="Vogen" Version="3.0.16" />
  </ItemGroup>
<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


// See https://aka.ms/new-console-template for more information

using DemoVogen;

Console.WriteLine("Hello, World!");
var p = PersonId.From(123);
var p1 = PersonId.From(123);
var p2 =(PersonId) 123;

Console.WriteLine(p == 123);
Console.WriteLine(p == p1);
Console.WriteLine(p == p2);



// See https://aka.ms/new-console-template for more information
using Vogen;
namespace DemoVogen;
[ValueObject<int>]
public partial struct PersonId
{
}

 

The code that is generated is

// ------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a source generator named Vogen (https://github.com/SteveDunn/Vogen)
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
// ------------------------------------------------------------------------------

// Suppress warnings about [Obsolete] member usage in generated code.
#pragma warning disable CS0618

// Suppress warnings for 'Override methods on comparable types'.
#pragma warning disable CA1036

// Suppress Error MA0097 : A class that implements IComparable<T> or IComparable should override comparison operators
#pragma warning disable MA0097

// Suppress warning for 'The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.'
// The generator copies signatures from the BCL, e.g. for `TryParse`, and some of those have nullable annotations.
#pragma warning disable CS8669

// Suppress warnings about CS1591: Missing XML comment for publicly visible type or member 'Type_or_Member'
#pragma warning disable CS1591

using Vogen;

namespace DemoVogen
{

    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] 
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Vogen", "3.0.0.0")]
    [global::System.Text.Json.Serialization.JsonConverter(typeof(PersonIdSystemTextJsonConverter))]
[global::System.ComponentModel.TypeConverter(typeof(PersonIdTypeConverter))]

    [global::System.Diagnostics.DebuggerTypeProxyAttribute(typeof(PersonIdDebugView))]
    [global::System.Diagnostics.DebuggerDisplayAttribute("Underlying type: System.Int32, Value = { _value }")]
    public partial struct PersonId : global::System.IEquatable<PersonId>, global::System.IEquatable<System.Int32> ,  global::System.IComparable<PersonId>, global::System.IComparable
    {
#if DEBUG    
        private readonly global::System.Diagnostics.StackTrace _stackTrace = null;
#endif

        private readonly global::System.Boolean _isInitialized;
        
        private readonly System.Int32 _value;

        /// <summary>
        /// Gets the underlying <see cref="System.Int32" /> value if set, otherwise a <see cref="ValueObjectValidationException" /> is thrown.
        /// </summary>
        public readonly System.Int32 Value
        {
            [global::System.Diagnostics.DebuggerStepThroughAttribute]
            get
            {
                EnsureInitialized();
                return _value;
            }
        }

        [global::System.Diagnostics.DebuggerStepThroughAttribute]
        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
        public PersonId()
        {
#if DEBUG
            _stackTrace = new global::System.Diagnostics.StackTrace();
#endif

            _isInitialized = false;
            _value = default;
        }

        [global::System.Diagnostics.DebuggerStepThroughAttribute]
        private PersonId(System.Int32 value) 
        {
            _value = value;
            _isInitialized = true;
        }

        /// <summary>
        /// Builds an instance from the provided underlying type.
        /// </summary>
        /// <param name="value">The underlying type.</param>
        /// <returns>An instance of this type.</returns>
        public static PersonId From(System.Int32 value)
        {
            

            PersonId instance = new PersonId(value);

            

            return instance;
        }

        public static explicit operator PersonId(System.Int32 value) => From(value);
        public static explicit operator System.Int32(PersonId value) => value.Value;

        // only called internally when something has been deserialized into
        // its primitive type.
        private static PersonId Deserialize(System.Int32 value)
        {
            

            

            return new PersonId(value);
        }

        public readonly global::System.Boolean Equals(PersonId other)
        {
            // It's possible to create uninitialized instances via converters such as EfCore (HasDefaultValue), which call Equals.
            // We treat anything uninitialized as not equal to anything, even other uninitialized instances of this type.
            if(!_isInitialized || !other._isInitialized) return false;

            return global::System.Collections.Generic.EqualityComparer<System.Int32>.Default.Equals(Value, other.Value);
        }

        public readonly global::System.Boolean Equals(System.Int32 primitive) => Value.Equals(primitive);

        public readonly override global::System.Boolean Equals(global::System.Object obj)
        {
            return obj is PersonId && Equals((PersonId) obj);
        }

        public static global::System.Boolean operator ==(PersonId left, PersonId right) => Equals(left, right);
        public static global::System.Boolean operator !=(PersonId left, PersonId right) => !(left == right);

        public static global::System.Boolean operator ==(PersonId left, System.Int32 right) => Equals(left.Value, right);
        public static global::System.Boolean operator !=(PersonId left, System.Int32 right) => !Equals(left.Value, right);

        public static global::System.Boolean operator ==(System.Int32 left, PersonId right) => Equals(left, right.Value);
        public static global::System.Boolean operator !=(System.Int32 left, PersonId right) => !Equals(left, right.Value);

        public int CompareTo(PersonId other) => Value.CompareTo(other.Value);
        public int CompareTo(object other) {
            if(other == null) return 1;
            if(other is PersonId x) return CompareTo(x);
            throw new global::System.ArgumentException("Cannot compare to object as it is not of type PersonId", nameof(other));
        }

        
    /// <inheritdoc cref="int.TryParse(System.ReadOnlySpan{char}, System.Globalization.NumberStyles, System.IFormatProvider?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider, 
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, style, provider, out var r)) {
            result = From(r);
            return true;
        }

        result = default;
        return false;
    }

    /// <inheritdoc cref="int.TryParse(System.ReadOnlySpan{char}, System.IFormatProvider?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> s, global::System.IFormatProvider provider, 
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, provider, out var r)) {
            result = From(r);
            return true;
        }

        result = default;
        return false;
    }

    /// <inheritdoc cref="int.TryParse(System.ReadOnlySpan{char}, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(global::System.ReadOnlySpan<char> s, 
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, out var r)) {
            result = From(r);
            return true;
        }

        result = default;
        return false;
    }

    /// <inheritdoc cref="int.TryParse(string?, System.Globalization.NumberStyles, System.IFormatProvider?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(string s, global::System.Globalization.NumberStyles style, global::System.IFormatProvider provider, 
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, style, provider, out var r)) {
            result = From(r);
            return true;
        }

        result = default;
        return false;
    }

    /// <inheritdoc cref="int.TryParse(string?, System.IFormatProvider?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(string s, global::System.IFormatProvider provider, 
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, provider, out var r)) {
            result = From(r);
            return true;
        }

        result = default;
        return false;
    }

    /// <inheritdoc cref="int.TryParse(string?, out int)"/>
    /// <summary>
    /// </summary>
    /// <returns>
    /// The value created via the <see cref="From"/> method.
    /// </returns>
    /// <exception cref="ValueObjectValidationException">Thrown when the value can be parsed, but is not valid.</exception>
    public static global::System.Boolean TryParse(string s, 
#if NETCOREAPP3_0_OR_GREATER
[global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)]
#endif
 out PersonId result) {
        if(System.Int32.TryParse(s, out var r)) {
            result = From(r);
            return true;
        }

        result = default;
        return false;
    }


        public readonly override global::System.Int32 GetHashCode() => global::System.Collections.Generic.EqualityComparer<System.Int32>.Default.GetHashCode(_value);

        /// <summary>Returns the string representation of the underlying type</summary>
    /// <inheritdoc cref="System.Int32.ToString()" />
    public readonly override global::System.String ToString() =>_isInitialized ? Value.ToString() : "[UNINITIALIZED]";

        private readonly void EnsureInitialized()
        {
            if (!_isInitialized)
            {
#if DEBUG
                global::System.String message = "Use of uninitialized Value Object at: " + _stackTrace ?? "";
#else
                global::System.String message = "Use of uninitialized Value Object.";
#endif

                throw new global::Vogen.ValueObjectValidationException(message);
            }
        }

        
 
        
        class PersonIdSystemTextJsonConverter : global::System.Text.Json.Serialization.JsonConverter<PersonId>
        {
            public override PersonId Read(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
            {
                return PersonId.Deserialize(reader.GetInt32());
            }

            public override void Write(System.Text.Json.Utf8JsonWriter writer, PersonId value, global::System.Text.Json.JsonSerializerOptions options)
            {
                writer.WriteNumberValue(value.Value);
            }

#if NET6_0_OR_GREATER            
            public override PersonId ReadAsPropertyName(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Type typeToConvert, global::System.Text.Json.JsonSerializerOptions options)
            {
                return PersonId.Deserialize(global::System.Int32.Parse(reader.GetString(), global::System.Globalization.NumberStyles.Any, global::System.Globalization.CultureInfo.InvariantCulture));
            }

            public override void WriteAsPropertyName(System.Text.Json.Utf8JsonWriter writer, PersonId value, global::System.Text.Json.JsonSerializerOptions options)
            {
                writer.WritePropertyName(value.Value.ToString(global::System.Globalization.CultureInfo.InvariantCulture));
            }
#endif
        }


        class PersonIdTypeConverter : global::System.ComponentModel.TypeConverter
        {
            public override global::System.Boolean CanConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
            {
                return sourceType == typeof(global::System.Int32) || sourceType == typeof(global::System.String) || base.CanConvertFrom(context, sourceType);
            }

            public override global::System.Object ConvertFrom(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value)
            {
                return value switch
                {
                    global::System.Int32 intValue => PersonId.Deserialize(intValue),
                    global::System.String stringValue when !global::System.String.IsNullOrEmpty(stringValue) && global::System.Int32.TryParse(stringValue, out var result) => PersonId.Deserialize(result),
                    _ => base.ConvertFrom(context, culture, value),
                };
            }

            public override bool CanConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Type sourceType)
            {
                return sourceType == typeof(global::System.Int32) || sourceType == typeof(global::System.String) || base.CanConvertTo(context, sourceType);
            }

            public override object ConvertTo(global::System.ComponentModel.ITypeDescriptorContext context, global::System.Globalization.CultureInfo culture, global::System.Object value, global::System.Type destinationType)
            {
                if (value is PersonId idValue)
                {
                    if (destinationType == typeof(global::System.Int32))
                    {
                        return idValue.Value;
                    }

                    if (destinationType == typeof(global::System.String))
                    {
                        return idValue.Value.ToString();
                    }
                }

                return base.ConvertTo(context, culture, value, destinationType);
            }
        }





        internal sealed class PersonIdDebugView
        {
            private readonly PersonId _t;

            PersonIdDebugView(PersonId t)
            {
                _t = t;
            }

            public global::System.Boolean IsInitialized => _t._isInitialized;
            public global::System.String UnderlyingType => "System.Int32";
            public global::System.String Value => _t._isInitialized ? _t._value.ToString() : "[not initialized]" ;

            #if DEBUG
            public global::System.String CreatedWith => _t._stackTrace?.ToString() ?? "the From method";
            #endif

            public global::System.String Conversions => @"Default";
                }

}
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Vogen

RSCG – dunet

RSCG – dunet
 
 

name dunet
nuget https://www.nuget.org/packages/dunet/
link https://github.com/domn1995/dunet
author Domn Werner

Add union types to C# – similar with F#/TS discriminated unions

Check his examples- awesome

 

This is how you can use dunet .

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="Dunet" Version="1.8.0">
			<PrivateAssets>all</PrivateAssets>
			<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
		</PackageReference>
	</ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

</Project>


The code that you will use is


// See https://github.com/domn1995/dunet for more examples
using duneDemo;
Console.WriteLine(WhatIsTheString.FromString("1"));

Console.WriteLine(WhatIsTheString.FromString("Andrei"));

Console.WriteLine(WhatIsTheString.FromString("1970-04-16"));

Console.WriteLine("Enter something - 1, 1970-04-16 or Andrei !");
var readLine = Console.ReadLine();
var opt= WhatIsTheString.FromString(readLine);
Console.WriteLine(opt);
//if if it long
opt.MatchIsLong(
    l => Console.WriteLine("is long " + l.value),
    () => Console.WriteLine("is not long")
    ) ;
//C# switch
var x=opt switch
{
    WhatIsTheString.IsLong l => "is long " +l.value,
    WhatIsTheString.IsDate d=> "is date "+ d.value,
    WhatIsTheString.IsString s=>"is string "+ s.value,
    WhatIsTheString.IsNullWhiteSpace w=>"no data",
    _ => throw new NotImplementedException()

};
Console.WriteLine(x);







using Dunet;
namespace duneDemo;

[Union]
partial record WhatIsTheString
{
    partial record IsString(string value);
    partial record IsLong(long value);
    partial record IsDate(DateTime value);

    partial record IsNullWhiteSpace();

    public static WhatIsTheString FromString(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
            return new IsNullWhiteSpace();

        if(long.TryParse(value, out var longValue))
        {
            return new IsLong(longValue);
        }
        if(DateTime.TryParse(value, out var dateTimeValue))
        {
            return new IsDate(dateTimeValue);
        }
        return new IsString(value);
    }

}


 

The code that is generated is

using System;

namespace Dunet;

/// <summary>
/// Enables dunet union source generation for the decorated partial record.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
internal sealed class UnionAttribute : Attribute {}
#pragma warning disable 1591
namespace duneDemo;
abstract partial record WhatIsTheString
{
    private WhatIsTheString() {}

    public abstract TMatchOutput Match<TMatchOutput>(
        System.Func<IsString, TMatchOutput> @isString,
        System.Func<IsLong, TMatchOutput> @isLong,
        System.Func<IsDate, TMatchOutput> @isDate,
        System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
    );
    public abstract void Match(
        System.Action<IsString> @isString,
        System.Action<IsLong> @isLong,
        System.Action<IsDate> @isDate,
        System.Action<IsNullWhiteSpace> @isNullWhiteSpace
    );

    public abstract TMatchOutput Match<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsString, TMatchOutput> @isString,
        System.Func<TState, IsLong, TMatchOutput> @isLong,
        System.Func<TState, IsDate, TMatchOutput> @isDate,
        System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
    );
    public abstract void Match<TState>(
        TState state,
        System.Action<TState, IsString> @isString,
        System.Action<TState, IsLong> @isLong,
        System.Action<TState, IsDate> @isDate,
        System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
    );

    public abstract TMatchOutput MatchIsString<TMatchOutput>(
        System.Func<IsString, TMatchOutput> @isString,
        System.Func<TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsLong<TMatchOutput>(
        System.Func<IsLong, TMatchOutput> @isLong,
        System.Func<TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsDate<TMatchOutput>(
        System.Func<IsDate, TMatchOutput> @isDate,
        System.Func<TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
        System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
        System.Func<TMatchOutput> @else
    );

    public abstract void MatchIsString(
        System.Action<IsString> @isString,
        System.Action @else
    );
    public abstract void MatchIsLong(
        System.Action<IsLong> @isLong,
        System.Action @else
    );
    public abstract void MatchIsDate(
        System.Action<IsDate> @isDate,
        System.Action @else
    );
    public abstract void MatchIsNullWhiteSpace(
        System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
        System.Action @else
    );

    public abstract TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsString, TMatchOutput> @isString,
        System.Func<TState, TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsLong, TMatchOutput> @isLong,
        System.Func<TState, TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsDate, TMatchOutput> @isDate,
        System.Func<TState, TMatchOutput> @else
    );
    public abstract TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
        System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
        System.Func<TState, TMatchOutput> @else
    );

    public abstract void MatchIsString<TState>(
        TState state,
        System.Action<TState, IsString> @isString,
        System.Action<TState> @else
    );
    public abstract void MatchIsLong<TState>(
        TState state,
        System.Action<TState, IsLong> @isLong,
        System.Action<TState> @else
    );
    public abstract void MatchIsDate<TState>(
        TState state,
        System.Action<TState, IsDate> @isDate,
        System.Action<TState> @else
    );
    public abstract void MatchIsNullWhiteSpace<TState>(
        TState state,
        System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
        System.Action<TState> @else
    );

    public sealed partial record IsString : WhatIsTheString
    {
        public override TMatchOutput Match<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isString(this);
        public override void Match(
            System.Action<IsString> @isString,
            System.Action<IsLong> @isLong,
            System.Action<IsDate> @isDate,
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isString(this);
        public override TMatchOutput Match<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isString(state, this);
        public override void Match<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isString(state, this);
        public override TMatchOutput MatchIsString<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<TMatchOutput> @else
        ) => @isString(this);
        public override TMatchOutput MatchIsLong<TMatchOutput>(
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsDate<TMatchOutput>(
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override void MatchIsString(
            System.Action<IsString> @isString,
            System.Action @else
        ) => @isString(this);
        public override void MatchIsLong(
            System.Action<IsLong> @isLong,
            System.Action @else
        ) => @else();
        public override void MatchIsDate(
            System.Action<IsDate> @isDate,
            System.Action @else
        ) => @else();
        public override void MatchIsNullWhiteSpace(
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action @else
        ) => @else();
        public override TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, TMatchOutput> @else
        ) => @isString(state, this);
        public override TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override void MatchIsString<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState> @else
        ) => @isString(state, this);
        public override void MatchIsLong<TState>(
        TState state,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsDate<TState>(
        TState state,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsNullWhiteSpace<TState>(
        TState state,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action<TState> @else
        ) => @else(state);
    }

    public sealed partial record IsLong : WhatIsTheString
    {
        public override TMatchOutput Match<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isLong(this);
        public override void Match(
            System.Action<IsString> @isString,
            System.Action<IsLong> @isLong,
            System.Action<IsDate> @isDate,
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isLong(this);
        public override TMatchOutput Match<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isLong(state, this);
        public override void Match<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isLong(state, this);
        public override TMatchOutput MatchIsString<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsLong<TMatchOutput>(
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<TMatchOutput> @else
        ) => @isLong(this);
        public override TMatchOutput MatchIsDate<TMatchOutput>(
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override void MatchIsString(
            System.Action<IsString> @isString,
            System.Action @else
        ) => @else();
        public override void MatchIsLong(
            System.Action<IsLong> @isLong,
            System.Action @else
        ) => @isLong(this);
        public override void MatchIsDate(
            System.Action<IsDate> @isDate,
            System.Action @else
        ) => @else();
        public override void MatchIsNullWhiteSpace(
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action @else
        ) => @else();
        public override TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, TMatchOutput> @else
        ) => @isLong(state, this);
        public override TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override void MatchIsString<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsLong<TState>(
        TState state,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState> @else
        ) => @isLong(state, this);
        public override void MatchIsDate<TState>(
        TState state,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsNullWhiteSpace<TState>(
        TState state,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action<TState> @else
        ) => @else(state);
    }

    public sealed partial record IsDate : WhatIsTheString
    {
        public override TMatchOutput Match<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isDate(this);
        public override void Match(
            System.Action<IsString> @isString,
            System.Action<IsLong> @isLong,
            System.Action<IsDate> @isDate,
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isDate(this);
        public override TMatchOutput Match<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isDate(state, this);
        public override void Match<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isDate(state, this);
        public override TMatchOutput MatchIsString<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsLong<TMatchOutput>(
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsDate<TMatchOutput>(
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<TMatchOutput> @else
        ) => @isDate(this);
        public override TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override void MatchIsString(
            System.Action<IsString> @isString,
            System.Action @else
        ) => @else();
        public override void MatchIsLong(
            System.Action<IsLong> @isLong,
            System.Action @else
        ) => @else();
        public override void MatchIsDate(
            System.Action<IsDate> @isDate,
            System.Action @else
        ) => @isDate(this);
        public override void MatchIsNullWhiteSpace(
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action @else
        ) => @else();
        public override TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, TMatchOutput> @else
        ) => @isDate(state, this);
        public override TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override void MatchIsString<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsLong<TState>(
        TState state,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsDate<TState>(
        TState state,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState> @else
        ) => @isDate(state, this);
        public override void MatchIsNullWhiteSpace<TState>(
        TState state,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action<TState> @else
        ) => @else(state);
    }

    public sealed partial record IsNullWhiteSpace : WhatIsTheString
    {
        public override TMatchOutput Match<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isNullWhiteSpace(this);
        public override void Match(
            System.Action<IsString> @isString,
            System.Action<IsLong> @isLong,
            System.Action<IsDate> @isDate,
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isNullWhiteSpace(this);
        public override TMatchOutput Match<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
        ) => @isNullWhiteSpace(state, this);
        public override void Match<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace
        ) => @isNullWhiteSpace(state, this);
        public override TMatchOutput MatchIsString<TMatchOutput>(
            System.Func<IsString, TMatchOutput> @isString,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsLong<TMatchOutput>(
            System.Func<IsLong, TMatchOutput> @isLong,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsDate<TMatchOutput>(
            System.Func<IsDate, TMatchOutput> @isDate,
            System.Func<TMatchOutput> @else
        ) => @else();
        public override TMatchOutput MatchIsNullWhiteSpace<TMatchOutput>(
            System.Func<IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TMatchOutput> @else
        ) => @isNullWhiteSpace(this);
        public override void MatchIsString(
            System.Action<IsString> @isString,
            System.Action @else
        ) => @else();
        public override void MatchIsLong(
            System.Action<IsLong> @isLong,
            System.Action @else
        ) => @else();
        public override void MatchIsDate(
            System.Action<IsDate> @isDate,
            System.Action @else
        ) => @else();
        public override void MatchIsNullWhiteSpace(
            System.Action<IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action @else
        ) => @isNullWhiteSpace(this);
        public override TMatchOutput MatchIsString<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsString, TMatchOutput> @isString,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsLong<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsLong, TMatchOutput> @isLong,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsDate<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsDate, TMatchOutput> @isDate,
            System.Func<TState, TMatchOutput> @else
        ) => @else(state);
        public override TMatchOutput MatchIsNullWhiteSpace<TState, TMatchOutput>(
        TState state,
            System.Func<TState, IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
            System.Func<TState, TMatchOutput> @else
        ) => @isNullWhiteSpace(state, this);
        public override void MatchIsString<TState>(
        TState state,
            System.Action<TState, IsString> @isString,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsLong<TState>(
        TState state,
            System.Action<TState, IsLong> @isLong,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsDate<TState>(
        TState state,
            System.Action<TState, IsDate> @isDate,
            System.Action<TState> @else
        ) => @else(state);
        public override void MatchIsNullWhiteSpace<TState>(
        TState state,
            System.Action<TState, IsNullWhiteSpace> @isNullWhiteSpace,
            System.Action<TState> @else
        ) => @isNullWhiteSpace(state, this);
    }

}
#pragma warning restore 1591

#pragma warning disable 1591

namespace duneDemo;

internal static class WhatIsTheStringMatchExtensions
{
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsString, TMatchOutput> @isString,
        System.Func<WhatIsTheString.IsLong, TMatchOutput> @isLong,
        System.Func<WhatIsTheString.IsDate, TMatchOutput> @isDate,
        System.Func<WhatIsTheString.IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
    )
    => (await unionTask.ConfigureAwait(false)).Match(
            @isString,
            @isLong,
            @isDate,
            @isNullWhiteSpace
        );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsString, TMatchOutput> @isString,
        System.Func<WhatIsTheString.IsLong, TMatchOutput> @isLong,
        System.Func<WhatIsTheString.IsDate, TMatchOutput> @isDate,
        System.Func<WhatIsTheString.IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace
    )
    => (await unionTask.ConfigureAwait(false)).Match(
            @isString,
            @isLong,
            @isDate,
            @isNullWhiteSpace
        );
    public static async System.Threading.Tasks.Task MatchAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsString> @isString,
        System.Action<WhatIsTheString.IsLong> @isLong,
        System.Action<WhatIsTheString.IsDate> @isDate,
        System.Action<WhatIsTheString.IsNullWhiteSpace> @isNullWhiteSpace
    )
    => (await unionTask.ConfigureAwait(false)).Match(
            @isString,
            @isLong,
            @isDate,
            @isNullWhiteSpace
        );
    public static async System.Threading.Tasks.ValueTask MatchAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsString> @isString,
        System.Action<WhatIsTheString.IsLong> @isLong,
        System.Action<WhatIsTheString.IsDate> @isDate,
        System.Action<WhatIsTheString.IsNullWhiteSpace> @isNullWhiteSpace
    )
    => (await unionTask.ConfigureAwait(false)).Match(
            @isString,
            @isLong,
            @isDate,
            @isNullWhiteSpace
        );
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchIsStringAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsString, TMatchOutput> @isString,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsString(
                    @isString,
                    @else
                );
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchIsLongAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsLong, TMatchOutput> @isLong,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsLong(
                    @isLong,
                    @else
                );
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchIsDateAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsDate, TMatchOutput> @isDate,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsDate(
                    @isDate,
                    @else
                );
    public static async System.Threading.Tasks.Task<TMatchOutput> MatchIsNullWhiteSpaceAsync<TMatchOutput>(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsNullWhiteSpace(
                    @isNullWhiteSpace,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchIsStringAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsString, TMatchOutput> @isString,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsString(
                    @isString,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchIsLongAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsLong, TMatchOutput> @isLong,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsLong(
                    @isLong,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchIsDateAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsDate, TMatchOutput> @isDate,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsDate(
                    @isDate,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask<TMatchOutput> MatchIsNullWhiteSpaceAsync<TMatchOutput>(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Func<WhatIsTheString.IsNullWhiteSpace, TMatchOutput> @isNullWhiteSpace,
        System.Func<TMatchOutput> @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsNullWhiteSpace(
                    @isNullWhiteSpace,
                    @else
                );
    public static async System.Threading.Tasks.Task MatchIsStringAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsString> @isString,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsString(
                    @isString,
                    @else
                );
    public static async System.Threading.Tasks.Task MatchIsLongAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsLong> @isLong,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsLong(
                    @isLong,
                    @else
                );
    public static async System.Threading.Tasks.Task MatchIsDateAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsDate> @isDate,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsDate(
                    @isDate,
                    @else
                );
    public static async System.Threading.Tasks.Task MatchIsNullWhiteSpaceAsync(
        this System.Threading.Tasks.Task<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsNullWhiteSpace> @isNullWhiteSpace,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsNullWhiteSpace(
                    @isNullWhiteSpace,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask MatchIsStringAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsString> @isString,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsString(
                    @isString,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask MatchIsLongAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsLong> @isLong,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsLong(
                    @isLong,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask MatchIsDateAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsDate> @isDate,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsDate(
                    @isDate,
                    @else
                );
    public static async System.Threading.Tasks.ValueTask MatchIsNullWhiteSpaceAsync(
        this System.Threading.Tasks.ValueTask<WhatIsTheString> unionTask,
        System.Action<WhatIsTheString.IsNullWhiteSpace> @isNullWhiteSpace,
        System.Action @else
    )
        =>
            (await unionTask.ConfigureAwait(false))
                .MatchIsNullWhiteSpace(
                    @isNullWhiteSpace,
                    @else
                );
}
#pragma warning restore 1591

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/dunet

RSCG – AutoCtor

RSCG – AutoCtor
 
 

name AutoCtor
nuget https://www.nuget.org/packages/AutoCtor/
link
author Cameron MacFarland

Generate constructor from non-initialized fields

 

This is how you can use AutoCtor .

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>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
	<ItemGroup>
	  <PackageReference Include="AutoCtor" Version="1.0.0" />
	</ItemGroup>
</Project>


The code that you will use is


// See https://aka.ms/new-console-template for more information
using AutoCtorDemo;

Console.WriteLine("Hello, World!");

var p = new Person("Andrei", "Ignat");



using AutoCtor;

namespace AutoCtorDemo;

[AutoConstruct]
internal partial class Person
{
    private readonly string FirstName;
    private readonly string? LastName;

}


 

The code that is generated is

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#if AUTOCTOR_EMBED_ATTRIBUTES
namespace AutoCtor
{
    [System.Runtime.CompilerServices.CompilerGenerated]
    [System.AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)]
    [System.Diagnostics.Conditional("AUTOCTOR_USAGES")]
    internal sealed class AutoConstructAttribute : System.Attribute
    {
        [System.Runtime.CompilerServices.CompilerGenerated]
        public AutoConstructAttribute()
        {
        }
    }
}
#endif
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by https://github.com/distantcam/AutoCtor
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace AutoCtorDemo
{
	partial class Person
	{
		public Person(string FirstName, string LastName)
		{
			this.FirstName = FirstName;
			this.LastName = LastName;
		}
	}
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/AutoCtor

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.