Category: .NET Core

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

RSCG – QuickConstructor

RSCG – QuickConstructor
 
 

name QuickConstructor
nuget https://www.nuget.org/packages/QuickConstructor
link https://github.com/flavien/QuickConstructor
author Flavien Charlon

Fast add constructors that are read only FIELDS

Has multiple other features

 

This is how you can use QuickConstructor .

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


The code that you will use is


using QuickConstructorDemo;

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


using QuickConstructor.Attributes;

namespace QuickConstructorDemo;

[QuickConstructor]
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 the QuickConstructor source generator.
/// </auto-generated>

#nullable enable

namespace QuickConstructorDemo
{
    partial class Person
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Person" /> class.
        /// </summary>
        public Person(string @firstName, string? @lastName)
        {
            if (@firstName == null)
                throw new global::System.ArgumentNullException(nameof(@firstName));

            this.@FirstName = @firstName;
            this.@LastName = @lastName;
        }
    }
}

Code and pdf at

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

RSCG – System.Runtime.InteropServices

RSCG – System.Runtime.InteropServices
 
 

name System.Runtime.InteropServices
nuget https://www.nuget.org/packages/System.Runtime.InteropServices/
link https://learn.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke-source-generation
author Microsoft

Generate PInvoke calls

 

This is how you can use System.Runtime.InteropServices .

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>
		<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
	</PropertyGroup>
</Project>


The code that you will use is


WriteLine(MessageBoxW(IntPtr.Zero, "asd", "asd", 1));
//RSCG
WriteLine(MessageBoxW_LI(IntPtr.Zero, "asd", "asd", 1));



partial class DemoImport
{
    [DllImport("user32.dll", EntryPoint = "MessageBoxW", CharSet = CharSet.Unicode, SetLastError = true)]

    internal static extern int MessageBoxW(IntPtr hWnd, string lpText, string lpCaption, uint uType);


    [LibraryImport("user32.dll", EntryPoint = "MessageBoxW", SetLastError = true,
StringMarshalling = StringMarshalling.Utf16)]

    internal static partial int MessageBoxW_LI(IntPtr hWnd, string lpText, string lpCaption, uint uType);
}


global using static System.Console;
global using static DemoImport;
global using System.Runtime.InteropServices;


 

The code that is generated is

// <auto-generated/>
unsafe partial class DemoImport
{
    [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Interop.LibraryImportGenerator", "7.0.8.17405")]
    [System.Runtime.CompilerServices.SkipLocalsInitAttribute]
    internal static partial int MessageBoxW_LI(nint hWnd, string lpText, string lpCaption, uint uType)
    {
        int __lastError;
        int __retVal;
        // Pin - Pin data in preparation for calling the P/Invoke.
        fixed (void* __lpText_native = &global::System.Runtime.InteropServices.Marshalling.Utf16StringMarshaller.GetPinnableReference(lpText))
        fixed (void* __lpCaption_native = &global::System.Runtime.InteropServices.Marshalling.Utf16StringMarshaller.GetPinnableReference(lpCaption))
        {
            System.Runtime.InteropServices.Marshal.SetLastSystemError(0);
            __retVal = __PInvoke(hWnd, (ushort*)__lpText_native, (ushort*)__lpCaption_native, uType);
            __lastError = System.Runtime.InteropServices.Marshal.GetLastSystemError();
        }

        System.Runtime.InteropServices.Marshal.SetLastPInvokeError(__lastError);
        return __retVal;
        // Local P/Invoke
        [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint = "MessageBoxW", ExactSpelling = true)]
        static extern unsafe int __PInvoke(nint hWnd, ushort* lpText, ushort* lpCaption, uint uType);
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/System.Runtime.InteropServices

RSCG – AutoDeconstruct

 
 

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

Automatically add deconstruct for all types in an assembly

 

This is how you can use AutoDeconstruct .

The code that you start with is


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

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

  <ItemGroup>
    <PackageReference Include="AutoDeconstruct" Version="1.0.0" />
  </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
Console.WriteLine("Hello, World!");
var p = new Person();
p.FirstName = "Test";
p.LastName = "Ignat";
var (_, l, _ ) = p;
Console.WriteLine($"Last name is {l}");


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

public class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public string? Title { get; set; }
}

[NoAutoDeconstruct]
public class TestPerson
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    public string? Title { get; set; }

}

 

The code that is generated is

#nullable enable

public static partial class PersonExtensions
{
	public static void Deconstruct(this global::Person @self, out string? @firstName, out string? @lastName, out string? @title)
	{
		global::System.ArgumentNullException.ThrowIfNull(@self);
		(@firstName, @lastName, @title) =
			(@self.FirstName, @self.LastName, @self.Title);
	}
}

Code and pdf at

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

RSCG – RSCG_AMS

 
 

name RSCG_AMS
nuget https://www.nuget.org/packages/RSCG_AMS/
link https://github.com/ignatandrei/RSCG_AMS
author Ignat Andrei

Automatically registering the version, ci, commit id

 

This is how you can use RSCG_AMS .

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="AMS_Base" Version="2023.5.21.1551" />
    <PackageReference Include="RSCG_AMS" Version="2023.5.21.1551" ReferenceOutputAssembly="false" OutputItemType="Analyzer" />
  </ItemGroup>

</Project>


The code that you will use is


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

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

var amsAll = AboutMySoftware.AllDefinitions;
Console.WriteLine("Number definitions:" + amsAll?.Length);
foreach (var amsKV in amsAll)
{
    var ams = amsKV.Value;

    Console.WriteLine($"{amsKV.Key}.{nameof(ams.AssemblyName)} : {ams.AssemblyName}");
    Console.WriteLine($"{amsKV.Key}.{nameof(ams.DateGenerated)} : {ams.DateGenerated}");
    Console.WriteLine($"{amsKV.Key}.{nameof(ams.CommitId)} : {ams.CommitId}");
    Console.WriteLine($"{amsKV.Key}.{nameof(ams.RepoUrl)} : {ams.RepoUrl}");
    Console.WriteLine($"{amsKV.Key}.{nameof(ams.CISourceControl)} : {ams.CISourceControl}");
    Console.WriteLine($"{amsKV.Key}.{nameof(ams.Authors)} : {ams.Authors}");
    Console.WriteLine($"{amsKV.Key}.{nameof(ams.Version)} : {ams.Version}");
    Console.WriteLine($"{amsKV.Key}.{nameof(ams.User)} : {ams.User}");
    Console.WriteLine("versions" + ams.Versions?.Length);
    if (ams.Versions != null)
        foreach (var item in ams.Versions)
        {
            Console.WriteLine("release:" + item.Name);
            foreach (var merge in item.releaseDatas)
            {
                Console.WriteLine("=>merge:" + merge.Subject);
            }

        }
}




[assembly: AMS_Base.VersionReleased(Name = "WithVersioning", ISODateTime = "2022-04-02", recordData = AMS_Base.RecordData.Merges)]
[assembly: AMS_Base.VersionReleased(Name = "FutureRelease", ISODateTime = "9999-04-16", recordData = AMS_Base.RecordData.Merges)]


 

The code that is generated is

using System;
using AMS_Base;
namespace RSCG_AMSDemo { 
    /// <summary>
    /// this is the About My Software for 828469749970839076110119122
    /// </summary>
    public class XAboutMySoftware_828469749970839076110119122 :AboutMySoftware {
        /// <summary>
        /// starts when this module is loaded and 
        /// add the AMS tot the 
        /// </summary>
        [System.Runtime.CompilerServices.ModuleInitializer]
        public static void Add_AboutMySoftware_828469749970839076110119122(){
            AboutMySoftware.AddDefinition("RSCG_AMSDemo",new  XAboutMySoftware_828469749970839076110119122());      
        }
        /// <summary>
        /// constructor
        /// for AMS 828469749970839076110119122
        /// </summary>
        public XAboutMySoftware_828469749970839076110119122(){
            AssemblyName ="RSCG_AMSDemo" ; 
            DateGenerated = DateTime.ParseExact("20230521152410", "yyyyMMddHHmmss", null); 
            CommitId  = "not in a CI run" ; 
            RepoUrl ="https://ignatandrei.github.io/RSCG_AMS/runtimeMessages/NotFound.md" ; 
            CISourceControl = "not in a CI run" ; 
            SourceCommit = "https://ignatandrei.github.io/RSCG_AMS/runtimeMessages/NotFound.md" ; 
            Authors= "";
            Version= "";    
            EnvironmentVars =";User_Path;User_TEMP;User_OneDrive;User_OneDriveConsumer;User_OneDriveCommercial;User_POSH_THEMES_PATH;User_TMP;User_R_HOME;User_ChocolateyLastPathUpdate;Process_OneDriveConsumer;Process_ProgramFiles(x86);Process_ProgramW6432;Process_windir;Process_ChocolateyInstall;Process_PROCESSOR_IDENTIFIER;Process_POWERSHELL_DISTRIBUTION_CHANNEL;Process_TMP;Process_PROCESSOR_ARCHITECTURE;Process_Path;Process_PkgDefApplicationConfigFile;Process_USERPROFILE;Process_VisualStudioDir;Process_PROCESSOR_REVISION;Process_ChocolateyLastPathUpdate;Process_FPS_BROWSER_APP_PROFILE_STRING;Process_FPS_BROWSER_USER_PROFILE_STRING;Process_LOGONSERVER;Process_TEMP;Process_USERNAME;Process_SystemRoot;Process_VSSKUEDITION;Process_MSMPI_BIN;Process_OneDrive;Process_LOCALAPPDATA;Process_CommonProgramFiles;Process_R_HOME;Process_ProgramData;Process_VS_Perf_Session_GCHeapCount;Process_VSAPPIDDIR;Process_HOMEPATH;Process_COMPUTERNAME;Process_MONO_ANDROID_PATH;Process_ALLUSERSPROFILE;Process_CommonProgramW6432;Process_OneDriveCommercial;Process_ThreadedWaitDialogDpiContext;Process_GCExpConfigUsedInSession;Process_SignInWithHomeTenantOnly;Process_SESSIONNAME;Process_DriverData;Process_HOMEDRIVE;Process_MSMPI_BENCHMARKS;Process_SystemDrive;Process_NUMBER_OF_PROCESSORS;Process_OS;Process_XAMARIN_ANDROID_REGKEY;Process_ProgramFiles;Process_ComSpec;Process_VSAPPIDNAME;Process_USERDOMAIN_ROAMINGPROFILE;Process_PATHEXT;Process_VSLANG;Process_PSModulePath;Process_APPDATA;Process_USERDOMAIN;Process_PROCESSOR_LEVEL;Process_POSH_THEMES_PATH;Process_VisualStudioVersion;Process_VisualStudioEdition;Process_ServiceHubLogSessionKey;Process_CommonProgramFiles(x86);Process_PUBLIC;Process_ForceIdentityAuthenticationType;Process_MSBuildLoadMicrosoftTargetsReadOnly;Machine_PROCESSOR_REVISION;Machine_ComSpec;Machine_TEMP;Machine_PROCESSOR_LEVEL;Machine_windir;Machine_POWERSHELL_DISTRIBUTION_CHANNEL;Machine_MSMPI_BIN;Machine_DriverData;Machine_PATHEXT;Machine_Path;Machine_NUMBER_OF_PROCESSORS;Machine_PSModulePath;Machine_TMP;Machine_ChocolateyInstall;Machine_MSMPI_BENCHMARKS;Machine_PROCESSOR_ARCHITECTURE;Machine_USERNAME;Machine_PROCESSOR_IDENTIFIER;Machine_OS";
            User = "Surface1";
            IsInCI=false;
            
{ var v=new VersionReleased();
v.Name = "FutureRelease" ;
v.ISODateTime=DateTime.ParseExact("99990416","yyyyMMdd",null); { 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "efd1aa541ad0117edfbb55eda5afc92179debb13";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230521","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "e458336035ec3f6c8b2096de21ab6a2a2e4377aa";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230519","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "d4d900aedf110891ff6fd974a4230f3e64fa8fbf";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230519","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "497f016ee38ed84ad46a224af224dcc079b212a3";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230518","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "752c2603c69d068d6f3cc533dea4febb3ffcc490";
rd.Subject = "Merge pull request #60 from ignatandrei/40-httpsgithubcomltrzesniewskirazorblade";
rd.ReleaseDate = DateTime.ParseExact("20230516","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "85c7e47e29fa4aac1f8bc2451ba3f89938a35e6b";
rd.Subject = "Merge pull request #59 from ignatandrei/35-httpsgithubcomdomn1995dunet";
rd.ReleaseDate = DateTime.ParseExact("20230516","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "74e4bc7adaf110c80d328b957ae6c302969b427c";
rd.Subject = "Merge pull request #58 from ignatandrei/36-httpsgithubcomdistantcamautoctor";
rd.ReleaseDate = DateTime.ParseExact("20230516","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "e6f03e4eaf45c7edbafd6c888f1cc9eee9295ec7";
rd.Subject = "Merge pull request #57 from ignatandrei/37-httpsgithubcomflavienquickconstructor";
rd.ReleaseDate = DateTime.ParseExact("20230515","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "01c13b88674c19f18f3229b3be0643e454fdfb5b";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230515","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "e559ea3ab9adc9cae60dbc942c811eac1dd51e25";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230515","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "201637618cebc273144a4bfb7211a2055c16e80d";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230514","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "a72f3a36c876def2e6c438c3a3c24abe7ba1db0d";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230514","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "c0c54da6c25e12bd886698022ac57f7b11fb8c4c";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230513","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "4c6fbf61eda86bcf2d049462913853ec8c52f1b2";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230513","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "56622984f6dddeca95a0f38f8d0809b96470fdff";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230513","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "f0caab198c26eb1a21e8e341d094222f689cd13f";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230512","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "87d3b7833fc8f99d41683fa3fcee088a7adfed85";
rd.Subject = "Merge pull request #54 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20230511","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "f68ad7b997593ded5e2ba60f65bf0ac295ae36f3";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230510","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "e5e9d0bbb7428cc1950eda609ce618d1394c9a89";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230509","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "95c1e2325ad41b28848a76c98e3b200aaa908a29";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples";
rd.ReleaseDate = DateTime.ParseExact("20230509","yyyyMMdd",null);  
v.AddRelease(rd);
} this.AddVersion(v);}
{ var v=new VersionReleased();
v.Name = "WithVersioning" ;
v.ISODateTime=DateTime.ParseExact("20220402","yyyyMMdd",null); { 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "c5c219a2a3cb26b8d1a46d632cf2dee54653602c";
rd.Subject = "Merge pull request #23 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20211016","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "1b6d21a19e8bc4ec9323d4369b8958d5563b0015";
rd.Subject = "Merge pull request #22 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20211011","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "ignatandrei";
rd.CommitId = "6d47fdc34ac4dc999f2e13fd828cd9f79f3bd41b";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples into main";
rd.ReleaseDate = DateTime.ParseExact("20211005","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "c3778675e5bfbeaa81667ada1fa24a19cf0e1efc";
rd.Subject = "Merge pull request #21 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20211003","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "ea755c59323eefd5c2ff7b2c34220ac5f8dbeaeb";
rd.Subject = "Merge pull request #20 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210901","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "1ea5abc7b06c3776fd49a991234d63e141a9d1e4";
rd.Subject = "Merge pull request #19 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210831","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "da6a848014673e96e07f64f00106f050d539142d";
rd.Subject = "Merge pull request #18 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210821","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "5bccff438ec6604d7eb45925a4714276b0b4bf16";
rd.Subject = "Merge pull request #17 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210815","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "17aebf5d69a448572ce4fd831f3dd94d56099956";
rd.Subject = "Merge pull request #16 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210815","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "83e209f09c4511a0e5607925fa730658f0940287";
rd.Subject = "Merge pull request #12 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210807","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "072cfeeda71acb1d84961291e962b4eab90b16a5";
rd.Subject = "Merge pull request #11 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210717","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "9172c92711d71da5e5c6aa8929f8ff6a8ac85b9e";
rd.Subject = "Merge pull request #10 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210625","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "918954a5ac28eb47e041faa90990ffd85a4a3499";
rd.Subject = "Merge pull request #7 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210621","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "16d62359fc7d807ed652fd9b4218b4aa04734d43";
rd.Subject = "Merge pull request #5 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210330","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "ignatandrei";
rd.CommitId = "3b082c0aa0f63effd098a2bad184b03447406ec0";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples into main";
rd.ReleaseDate = DateTime.ParseExact("20210308","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "1a998fa87363c6df6b6d4a09dc514503808d380f";
rd.Subject = "Merge pull request #4 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210308","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "c5fa74a2ad780af288ece391da7a5ac84b06332e";
rd.Subject = "Merge pull request #3 from ignatandrei/imgbot";
rd.ReleaseDate = DateTime.ParseExact("20210307","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "ignatandrei";
rd.CommitId = "1bedfd1d4cb00f666b94fdaecdd7bd7da2e6a435";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples into main";
rd.ReleaseDate = DateTime.ParseExact("20210302","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "ignatandrei";
rd.CommitId = "3223ba3b8e69fc9e72e34735cc135b39881f7b59";
rd.Subject = "Merge branch 'main' of https://github.com/ignatandrei/RSCG_Examples into main";
rd.ReleaseDate = DateTime.ParseExact("20210218","yyyyMMdd",null);  
v.AddRelease(rd);
}{ 
var rd=new ReleaseData();
rd.Author = "Andrei Ignat";
rd.CommitId = "bea2886eb02f17523a34ff16f475654cb4b24ff4";
rd.Subject = "Merge pull request #1 from ignatandrei/whitesource/configure";
rd.ReleaseDate = DateTime.ParseExact("20210217","yyyyMMdd",null);  
v.AddRelease(rd);
} this.AddVersion(v);}
        }
        
    }
        
}

Code and pdf at

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

RSCG – CommunityToolkit.Mvvm

name CommunityToolkit.Mvvm
nuget https://www.nuget.org/packages/CommunityToolkit.Mvvm
link https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/overview
author Microsoft

Shows how to implement INotifyPropertyChanged,ObservableProperty and RelayCommand

Unfortunately , not yet a separate package just for those.

Also, this show that RSCG could generate multiple partial declarations

 

This is how you can use CommunityToolkit.Mvvm .

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="CommunityToolkit.Mvvm" Version="8.2.0" />
  </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 test;

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

MyViewModel myViewModel = new();
myViewModel.Name = "Andrei";
var x=myViewModel.SayHelloCommand;


using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

namespace test;

[INotifyPropertyChanged]
public partial class MyViewModel 
{
    [ObservableProperty]
    private string? name;

    [RelayCommand]
    private void SayHello()
    {
        Console.WriteLine("Hello");
    }
}


 

The code that is generated is

// <auto-generated/>
#pragma warning disable
#nullable enable
namespace test
{
    /// <inheritdoc/>
    partial class MyViewModel : global::System.ComponentModel.INotifyPropertyChanged
    {
        /// <inheritdoc cref = "global::System.ComponentModel.INotifyPropertyChanged.PropertyChanged"/>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        public event global::System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
        /// <summary>
        /// Raises the <see cref = "PropertyChanged"/> event.
        /// </summary>
        /// <param name = "e">The input <see cref = "global::System.ComponentModel.PropertyChangedEventArgs"/> instance.</param>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected virtual void OnPropertyChanged(global::System.ComponentModel.PropertyChangedEventArgs e)
        {
            PropertyChanged?.Invoke(this, e);
        }

        /// <summary>
        /// Raises the <see cref = "PropertyChanged"/> event.
        /// </summary>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected void OnPropertyChanged([global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            OnPropertyChanged(new global::System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Compares the current and new values for a given property. If the value has changed, updates
        /// the property with the new value, then raises the <see cref = "PropertyChanged"/> event.
        /// </summary>
        /// <typeparam name = "T">The type of the property that changed.</typeparam>
        /// <param name = "field">The field storing the property's value.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        /// <remarks>
        /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetProperty<T>([global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("newValue")] ref T field, T newValue, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            if (global::System.Collections.Generic.EqualityComparer<T>.Default.Equals(field, newValue))
            {
                return false;
            }

            field = newValue;
            OnPropertyChanged(propertyName);
            return true;
        }

        /// <summary>
        /// Compares the current and new values for a given property. If the value has changed, updates
        /// the property with the new value, then raises the <see cref = "PropertyChanged"/> event.
        /// See additional notes about this overload in <see cref = "SetProperty{T}(ref T, T, string)"/>.
        /// </summary>
        /// <typeparam name = "T">The type of the property that changed.</typeparam>
        /// <param name = "field">The field storing the property's value.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "comparer">The <see cref = "global::System.Collections.Generic.IEqualityComparer{T}"/> instance to use to compare the input values.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetProperty<T>([global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("newValue")] ref T field, T newValue, global::System.Collections.Generic.IEqualityComparer<T> comparer, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            if (comparer.Equals(field, newValue))
            {
                return false;
            }

            field = newValue;
            OnPropertyChanged(propertyName);
            return true;
        }

        /// <summary>
        /// Compares the current and new values for a given property. If the value has changed, updates
        /// the property with the new value, then raises the <see cref = "PropertyChanged"/> event.
        /// This overload is much less efficient than <see cref = "SetProperty{T}(ref T, T, string)"/> and it
        /// should only be used when the former is not viable (eg. when the target property being
        /// updated does not directly expose a backing field that can be passed by reference).
        /// For performance reasons, it is recommended to use a stateful callback if possible through
        /// the <see cref = "SetProperty{TModel, T}(T, T, TModel, global::System.Action{TModel, T}, string? )"/> whenever possible
        /// instead of this overload, as that will allow the C# compiler to cache the input callback and
        /// reduce the memory allocations. More info on that overload are available in the related XML
        /// docs. This overload is here for completeness and in cases where that is not applicable.
        /// </summary>
        /// <typeparam name = "T">The type of the property that changed.</typeparam>
        /// <param name = "oldValue">The current property value.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "callback">A callback to invoke to update the property value.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        /// <remarks>
        /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetProperty<T>(T oldValue, T newValue, global::System.Action<T> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            if (global::System.Collections.Generic.EqualityComparer<T>.Default.Equals(oldValue, newValue))
            {
                return false;
            }

            callback(newValue);
            OnPropertyChanged(propertyName);
            return true;
        }

        /// <summary>
        /// Compares the current and new values for a given property. If the value has changed, updates
        /// the property with the new value, then raises the <see cref = "PropertyChanged"/> event.
        /// See additional notes about this overload in <see cref = "SetProperty{T}(T, T, global::System.Action{T}, string)"/>.
        /// </summary>
        /// <typeparam name = "T">The type of the property that changed.</typeparam>
        /// <param name = "oldValue">The current property value.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "comparer">The <see cref = "global::System.Collections.Generic.IEqualityComparer{T}"/> instance to use to compare the input values.</param>
        /// <param name = "callback">A callback to invoke to update the property value.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetProperty<T>(T oldValue, T newValue, global::System.Collections.Generic.IEqualityComparer<T> comparer, global::System.Action<T> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            if (comparer.Equals(oldValue, newValue))
            {
                return false;
            }

            callback(newValue);
            OnPropertyChanged(propertyName);
            return true;
        }

        /// <summary>
        /// Compares the current and new values for a given nested property. If the value has changed,
        /// updates the property and then raises the <see cref = "PropertyChanged"/> event.
        /// The behavior mirrors that of <see cref = "SetProperty{T}(ref T, T, string)"/>,
        /// with the difference being that this method is used to relay properties from a wrapped model in the
        /// current instance. This type is useful when creating wrapping, bindable objects that operate over
        /// models that lack support for notification (eg. for CRUD operations).
        /// Suppose we have this model (eg. for a database row in a table):
        /// <code>
        /// public class Person
        /// {
        ///     public string Name { get; set; }
        /// }
        /// </code>
        /// We can then use a property to wrap instances of this type into our observable model (which supports
        /// notifications), injecting the notification to the properties of that model, like so:
        /// <code>
        /// [INotifyPropertyChanged]
        /// public partial class BindablePerson
        /// {
        ///     public Model { get; }
        ///
        ///     public BindablePerson(Person model)
        ///     {
        ///         Model = model;
        ///     }
        ///
        ///     public string Name
        ///     {
        ///         get => Model.Name;
        ///         set => Set(Model.Name, value, Model, (model, name) => model.Name = name);
        ///     }
        /// }
        /// </code>
        /// This way we can then use the wrapping object in our application, and all those "proxy" properties will
        /// also raise notifications when changed. Note that this method is not meant to be a replacement for
        /// <see cref = "SetProperty{T}(ref T, T, string)"/>, and it should only be used when relaying properties to a model that
        /// doesn't support notifications, and only if you can't implement notifications to that model directly (eg. by having
        /// it implement <see cref = "global::System.ComponentModel.INotifyPropertyChanged"/>). The syntax relies on passing the target model and a stateless callback
        /// to allow the C# compiler to cache the function, which results in much better performance and no memory usage.
        /// </summary>
        /// <typeparam name = "TModel">The type of model whose property (or field) to set.</typeparam>
        /// <typeparam name = "T">The type of property (or field) to set.</typeparam>
        /// <param name = "oldValue">The current property value.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "model">The model containing the property being updated.</param>
        /// <param name = "callback">The callback to invoke to set the target property value, if a change has occurred.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        /// <remarks>
        /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetProperty<TModel, T>(T oldValue, T newValue, TModel model, global::System.Action<TModel, T> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
            where TModel : class
        {
            if (global::System.Collections.Generic.EqualityComparer<T>.Default.Equals(oldValue, newValue))
            {
                return false;
            }

            callback(model, newValue);
            OnPropertyChanged(propertyName);
            return true;
        }

        /// <summary>
        /// Compares the current and new values for a given nested property. If the value has changed,
        /// updates the property and then raises the <see cref = "PropertyChanged"/> event.
        /// The behavior mirrors that of <see cref = "SetProperty{T}(ref T, T, string)"/>,
        /// with the difference being that this method is used to relay properties from a wrapped model in the
        /// current instance. See additional notes about this overload in <see cref = "SetProperty{TModel, T}(T, T, TModel, global::System.Action{TModel, T}, string)"/>.
        /// </summary>
        /// <typeparam name = "TModel">The type of model whose property (or field) to set.</typeparam>
        /// <typeparam name = "T">The type of property (or field) to set.</typeparam>
        /// <param name = "oldValue">The current property value.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "comparer">The <see cref = "global::System.Collections.Generic.IEqualityComparer{T}"/> instance to use to compare the input values.</param>
        /// <param name = "model">The model containing the property being updated.</param>
        /// <param name = "callback">The callback to invoke to set the target property value, if a change has occurred.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetProperty<TModel, T>(T oldValue, T newValue, global::System.Collections.Generic.IEqualityComparer<T> comparer, TModel model, global::System.Action<TModel, T> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
            where TModel : class
        {
            if (comparer.Equals(oldValue, newValue))
            {
                return false;
            }

            callback(model, newValue);
            OnPropertyChanged(propertyName);
            return true;
        }

        /// <summary>
        /// Compares the current and new values for a given field (which should be the backing field for a property).
        /// If the value has changed, updates the field and then raises the <see cref = "PropertyChanged"/> event.
        /// The behavior mirrors that of <see cref = "SetProperty{T}(ref T, T, string)"/>, with the difference being that
        /// this method will also monitor the new value of the property (a generic <see cref = "global::System.Threading.Tasks.Task"/>) and will also
        /// raise the <see cref = "PropertyChanged"/> again for the target property when it completes.
        /// This can be used to update bindings observing that <see cref = "global::System.Threading.Tasks.Task"/> or any of its properties.
        /// This method and its overload specifically rely on the <see cref = "TaskNotifier"/> type, which needs
        /// to be used in the backing field for the target <see cref = "global::System.Threading.Tasks.Task"/> property. The field doesn't need to be
        /// initialized, as this method will take care of doing that automatically. The <see cref = "TaskNotifier"/>
        /// type also includes an implicit operator, so it can be assigned to any <see cref = "global::System.Threading.Tasks.Task"/> instance directly.
        /// Here is a sample property declaration using this method:
        /// <code>
        /// private TaskNotifier myTask;
        ///
        /// public Task MyTask
        /// {
        ///     get => myTask;
        ///     private set => SetAndNotifyOnCompletion(ref myTask, value);
        /// }
        /// </code>
        /// </summary>
        /// <param name = "taskNotifier">The field notifier to modify.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        /// <remarks>
        /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are
        /// the same. The return value being <see langword="true"/> only indicates that the new value being assigned to
        /// <paramref name = "taskNotifier"/> is different than the previous one, and it does not mean the new
        /// <see cref = "global::System.Threading.Tasks.Task"/> instance passed as argument is in any particular state.
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetPropertyAndNotifyOnCompletion([global::System.Diagnostics.CodeAnalysis.NotNull] ref TaskNotifier? taskNotifier, global::System.Threading.Tasks.Task? newValue, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier(), newValue, null, propertyName);
        }

        /// <summary>
        /// Compares the current and new values for a given field (which should be the backing field for a property).
        /// If the value has changed, updates the field and then raises the <see cref = "PropertyChanged"/> event.
        /// This method is just like <see cref = "SetPropertyAndNotifyOnCompletion(ref TaskNotifier, global::System.Threading.Tasks.Task, string)"/>,
        /// with the difference being an extra <see cref = "global::System.Action{T}"/> parameter with a callback being invoked
        /// either immediately, if the new task has already completed or is <see langword="null"/>, or upon completion.
        /// </summary>
        /// <param name = "taskNotifier">The field notifier to modify.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "callback">A callback to invoke to update the property value.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        /// <remarks>
        /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetPropertyAndNotifyOnCompletion([global::System.Diagnostics.CodeAnalysis.NotNull] ref TaskNotifier? taskNotifier, global::System.Threading.Tasks.Task? newValue, global::System.Action<global::System.Threading.Tasks.Task?> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier(), newValue, callback, propertyName);
        }

        /// <summary>
        /// Compares the current and new values for a given field (which should be the backing field for a property).
        /// If the value has changed, updates the field and then raises the <see cref = "PropertyChanged"/> event.
        /// The behavior mirrors that of <see cref = "SetProperty{T}(ref T, T, string)"/>, with the difference being that
        /// this method will also monitor the new value of the property (a generic <see cref = "global::System.Threading.Tasks.Task"/>) and will also
        /// raise the <see cref = "PropertyChanged"/> again for the target property when it completes.
        /// This can be used to update bindings observing that <see cref = "global::System.Threading.Tasks.Task"/> or any of its properties.
        /// This method and its overload specifically rely on the <see cref = "TaskNotifier{T}"/> type, which needs
        /// to be used in the backing field for the target <see cref = "global::System.Threading.Tasks.Task"/> property. The field doesn't need to be
        /// initialized, as this method will take care of doing that automatically. The <see cref = "TaskNotifier{T}"/>
        /// type also includes an implicit operator, so it can be assigned to any <see cref = "global::System.Threading.Tasks.Task"/> instance directly.
        /// Here is a sample property declaration using this method:
        /// <code>
        /// private TaskNotifier&lt;int&gt; myTask;
        ///
        /// public Task&lt;int&gt; MyTask
        /// {
        ///     get => myTask;
        ///     private set => SetAndNotifyOnCompletion(ref myTask, value);
        /// }
        /// </code>
        /// </summary>
        /// <typeparam name = "T">The type of result for the <see cref = "global::System.Threading.Tasks.Task{TResult}"/> to set and monitor.</typeparam>
        /// <param name = "taskNotifier">The field notifier to modify.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        /// <remarks>
        /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are
        /// the same. The return value being <see langword="true"/> only indicates that the new value being assigned to
        /// <paramref name = "taskNotifier"/> is different than the previous one, and it does not mean the new
        /// <see cref = "global::System.Threading.Tasks.Task{TResult}"/> instance passed as argument is in any particular state.
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetPropertyAndNotifyOnCompletion<T>([global::System.Diagnostics.CodeAnalysis.NotNull] ref TaskNotifier<T>? taskNotifier, global::System.Threading.Tasks.Task<T>? newValue, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier<T>(), newValue, null, propertyName);
        }

        /// <summary>
        /// Compares the current and new values for a given field (which should be the backing field for a property).
        /// If the value has changed, updates the field and then raises the <see cref = "PropertyChanged"/> event.
        /// This method is just like <see cref = "SetPropertyAndNotifyOnCompletion{T}(ref TaskNotifier{T}, global::System.Threading.Tasks.Task{T}, string)"/>,
        /// with the difference being an extra <see cref = "global::System.Action{T}"/> parameter with a callback being invoked
        /// either immediately, if the new task has already completed or is <see langword="null"/>, or upon completion.
        /// </summary>
        /// <typeparam name = "T">The type of result for the <see cref = "global::System.Threading.Tasks.Task{TResult}"/> to set and monitor.</typeparam>
        /// <param name = "taskNotifier">The field notifier to modify.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "callback">A callback to invoke to update the property value.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        /// <remarks>
        /// The <see cref = "PropertyChanged"/> event is not raised if the current and new value for the target property are the same.
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected bool SetPropertyAndNotifyOnCompletion<T>([global::System.Diagnostics.CodeAnalysis.NotNull] ref TaskNotifier<T>? taskNotifier, global::System.Threading.Tasks.Task<T>? newValue, global::System.Action<global::System.Threading.Tasks.Task<T>?> callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            return SetPropertyAndNotifyOnCompletion(taskNotifier ??= new TaskNotifier<T>(), newValue, callback, propertyName);
        }

        /// <summary>
        /// Implements the notification logic for the related methods.
        /// </summary>
        /// <typeparam name = "TTask">The type of <see cref = "global::System.Threading.Tasks.Task"/> to set and monitor.</typeparam>
        /// <param name = "taskNotifier">The field notifier.</param>
        /// <param name = "newValue">The property's value after the change occurred.</param>
        /// <param name = "callback">(optional) A callback to invoke to update the property value.</param>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        private bool SetPropertyAndNotifyOnCompletion<TTask>(ITaskNotifier<TTask> taskNotifier, TTask? newValue, global::System.Action<TTask?>? callback, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
            where TTask : global::System.Threading.Tasks.Task
        {
            if (ReferenceEquals(taskNotifier.Task, newValue))
            {
                return false;
            }

            bool isAlreadyCompletedOrNull = newValue?.IsCompleted ?? true;
            taskNotifier.Task = newValue;
            OnPropertyChanged(propertyName);
            if (isAlreadyCompletedOrNull)
            {
                if (callback != null)
                {
                    callback(newValue);
                }

                return true;
            }

            async void MonitorTask()
            {
                await global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__TaskExtensions.GetAwaitableWithoutEndValidation(newValue!);
                if (ReferenceEquals(taskNotifier.Task, newValue))
                {
                    OnPropertyChanged(propertyName);
                }

                if (callback != null)
                {
                    callback(newValue);
                }
            }

            MonitorTask();
            return true;
        }

        /// <summary>
        /// An interface for task notifiers of a specified type.
        /// </summary>
        /// <typeparam name = "TTask">The type of value to store.</typeparam>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        private interface ITaskNotifier<TTask>
            where TTask : global::System.Threading.Tasks.Task
        {
            /// <summary>
            /// Gets or sets the wrapped <typeparamref name = "TTask"/> value.
            /// </summary>
            TTask? Task { get; set; }
        }

        /// <summary>
        /// A wrapping class that can hold a <see cref = "global::System.Threading.Tasks.Task"/> value.
        /// </summary>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected sealed class TaskNotifier : ITaskNotifier<global::System.Threading.Tasks.Task>
        {
            /// <summary>
            /// Initializes a new instance of the <see cref = "TaskNotifier"/> class.
            /// </summary>
            internal TaskNotifier()
            {
            }

            private global::System.Threading.Tasks.Task? task;
            /// <inheritdoc/>
            global::System.Threading.Tasks.Task? ITaskNotifier<global::System.Threading.Tasks.Task>.Task { get => this.task; set => this.task = value; }

            /// <summary>
            /// Unwraps the <see cref = "global::System.Threading.Tasks.Task"/> value stored in the current instance.
            /// </summary>
            /// <param name = "notifier">The input <see cref = "TaskNotifier{TTask}"/> instance.</param>
            public static implicit operator global::System.Threading.Tasks.Task? (TaskNotifier? notifier)
            {
                return notifier?.task;
            }
        }

        /// <summary>
        /// A wrapping class that can hold a <see cref = "global::System.Threading.Tasks.Task{T}"/> value.
        /// </summary>
        /// <typeparam name = "T">The type of value for the wrapped <see cref = "global::System.Threading.Tasks.Task{T}"/> instance.</typeparam>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.2.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected sealed class TaskNotifier<T> : ITaskNotifier<global::System.Threading.Tasks.Task<T>>
        {
            /// <summary>
            /// Initializes a new instance of the <see cref = "TaskNotifier{TTask}"/> class.
            /// </summary>
            internal TaskNotifier()
            {
            }

            private global::System.Threading.Tasks.Task<T>? task;
            /// <inheritdoc/>
            global::System.Threading.Tasks.Task<T>? ITaskNotifier<global::System.Threading.Tasks.Task<T>>.Task { get => this.task; set => this.task = value; }

            /// <summary>
            /// Unwraps the <see cref = "global::System.Threading.Tasks.Task{T}"/> value stored in the current instance.
            /// </summary>
            /// <param name = "notifier">The input <see cref = "TaskNotifier{TTask}"/> instance.</param>
            public static implicit operator global::System.Threading.Tasks.Task<T>? (TaskNotifier<T>? notifier)
            {
                return notifier?.task;
            }
        }
    }
}
// <auto-generated/>
#pragma warning disable
#nullable enable
namespace test
{
    /// <inheritdoc/>
    partial class MyViewModel
    {
        /// <inheritdoc cref="name"/>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        public string? Name
        {
            get => name;
            set
            {
                if (!global::System.Collections.Generic.EqualityComparer<string?>.Default.Equals(name, value))
                {
                    OnNameChanging(value);
                    OnNameChanging(default, value);
                    name = value;
                    OnNameChanged(value);
                    OnNameChanged(default, value);
                    OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.Name);
                }
            }
        }

        /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
        /// <param name="value">The new property value being set.</param>
        /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")]
        partial void OnNameChanging(string? value);
        /// <summary>Executes the logic for when <see cref="Name"/> is changing.</summary>
        /// <param name="oldValue">The previous property value that is being replaced.</param>
        /// <param name="newValue">The new property value being set.</param>
        /// <remarks>This method is invoked right before the value of <see cref="Name"/> is changed.</remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")]
        partial void OnNameChanging(string? oldValue, string? newValue);
        /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
        /// <param name="value">The new property value that was set.</param>
        /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")]
        partial void OnNameChanged(string? value);
        /// <summary>Executes the logic for when <see cref="Name"/> just changed.</summary>
        /// <param name="oldValue">The previous property value that was replaced.</param>
        /// <param name="newValue">The new property value that was set.</param>
        /// <remarks>This method is invoked right after the value of <see cref="Name"/> is changed.</remarks>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")]
        partial void OnNameChanged(string? oldValue, string? newValue);
    }
}
// <auto-generated/>
#pragma warning disable
#nullable enable
namespace CommunityToolkit.Mvvm.ComponentModel.__Internals
{
    /// <summary>
    /// A helper type providing cached, reusable <see cref="global::System.ComponentModel.PropertyChangedEventArgs"/> instances
    /// for all properties generated with <see cref="global::CommunityToolkit.Mvvm.ComponentModel.ObservablePropertyAttribute"/>.
    /// </summary>
    [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.2.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCode]
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
    [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
    [global::System.Obsolete("This type is not intended to be used directly by user code")]
    internal static class __KnownINotifyPropertyChangedArgs
    {
        /// <summary>The cached <see cref="global::System.ComponentModel.PropertyChangedEventArgs"/> instance for all "Name" generated properties.</summary>
        [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]
        [global::System.Obsolete("This field is not intended to be referenced directly by user code")]
        public static readonly global::System.ComponentModel.PropertyChangedEventArgs Name = new global::System.ComponentModel.PropertyChangedEventArgs("Name");
    }
}
// <auto-generated/>
#pragma warning disable
#nullable enable
namespace test
{
    /// <inheritdoc/>
    partial class MyViewModel
    {
        /// <summary>The backing field for <see cref="SayHelloCommand"/>.</summary>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.RelayCommandGenerator", "8.2.0.0")]
        private global::CommunityToolkit.Mvvm.Input.RelayCommand? sayHelloCommand;
        /// <summary>Gets an <see cref="global::CommunityToolkit.Mvvm.Input.IRelayCommand"/> instance wrapping <see cref="SayHello"/>.</summary>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.RelayCommandGenerator", "8.2.0.0")]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        public global::CommunityToolkit.Mvvm.Input.IRelayCommand SayHelloCommand => sayHelloCommand ??= new global::CommunityToolkit.Mvvm.Input.RelayCommand(new global::System.Action(SayHello));
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/CommunityToolkit.Mvvm

RSCG – RSCG_Static

 
 

name RSCG_Static
nuget https://www.nuget.org/packages/RSCG_Static/
link https://github.com/ignatandrei/RSCG_Static
author Andrei Ignat

Generate interfaces and classes from static classes

 

This is how you can use RSCG_Static .

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="RSCG_Static" Version="2023.5.19.2037" />
	</ItemGroup>

</Project>


The code that you will use is


using RSCG_StaticDemo;
//for DI, register
//ISystem_DateTime  with transient for new clsSystem_DateTime()
Console.WriteLine("Hello World!");
ISystem_DateTime dateStatic = recSystem_DateTime.MakeNew();//static
ISystem_DateTime dateVar = new clsSystem_DateTime(); //variable = real 

Console.WriteLine(dateStatic.Now.Second);
Console.WriteLine(dateVar.Now.Second);
await Task.Delay(10 * 1000);
Console.WriteLine(dateStatic.Now.Second);
Console.WriteLine(dateVar.Now.Second);



namespace RSCG_StaticDemo;

public partial class StaticToInterface
{
    public Type GenerateInterfaceFromDate() => typeof(DateTime);
}


 

The code that is generated is


#nullable enable
 namespace RSCG_StaticDemo {
      public interface ISystem_DateTime {
          public System.DateTime Now  {get;}
          public System.DateTime Today  {get;}
          public System.DateTime UtcNow  {get;}
      }// interface
//now the partial class
      public record recSystem_DateTime (System.DateTime Now,System.DateTime Today,System.DateTime UtcNow) : ISystem_DateTime
      { 
            public static recSystem_DateTime MakeNew() {
            return new recSystem_DateTime(System.DateTime.Now,System.DateTime.Today,System.DateTime.UtcNow);
            } //end makenew
      } //end record
      public class clsSystem_DateTime : ISystem_DateTime 
      { 
            public System.DateTime Now  {get { return System.DateTime.Now; } }
            public System.DateTime Today  {get { return System.DateTime.Today; } }
            public System.DateTime UtcNow  {get { return System.DateTime.UtcNow; } }
       } //end class
 } // namespace
#nullable disable

Code and pdf at

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

RSCG – Microsoft.Extensions.Logging

RSCG – Microsoft.Extensions.Logging
 
 

name Microsoft.Extensions.Logging
nuget https://www.nuget.org/packages/Microsoft.Extensions.Logging/
link https://learn.microsoft.com/en-us/dotnet/core/extensions/logger-message-generator-generators/
author Microsoft

Logging defined and compiled

 

This is how you can use Microsoft.Extensions.Logging .

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)\GeneratedX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
	<ItemGroup>
		<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
	</ItemGroup>
</Project>


The code that you will use is


using System.Text.Json;
using Microsoft.Extensions.Logging;

using ILoggerFactory loggerFactory = LoggerFactory.Create(
    builder =>
    //https://learn.microsoft.com/en-us/dotnet/core/extensions/console-log-formatter
    builder.AddSimpleConsole()
    //builder.AddJsonConsole(
    //    options =>
    //    options.JsonWriterOptions = new JsonWriterOptions()
    //    {
    //        Indented = true
    //    })
    ) ;

ILogger<SampleObject> logger = loggerFactory.CreateLogger<SampleObject>();
logger.LogInformation("test");
//https://learn.microsoft.com/en-us/dotnet/core/extensions/logger-message-generator
(new LoggingSample(logger)).TestLogging();
file readonly record struct SampleObject { }



using Microsoft.Extensions.Logging;

public partial class LoggingSample
{
    private readonly ILogger _logger;

    public LoggingSample(ILogger logger)
    {
        _logger = logger;
    }

    [LoggerMessage(
        EventId = 20,
        Level = LogLevel.Critical,
        Message = "Value is {value:E}")]
    public static partial void UsingFormatSpecifier(
        ILogger logger, double value);

    [LoggerMessage(
        EventId = 9,
        Level = LogLevel.Trace,
        Message = "Fixed message",
        EventName = "CustomEventName")]
    public partial void LogWithCustomEventName();

    [LoggerMessage(
        EventId = 10,
        Message = "Welcome to {city} {province}!")]
    public partial void LogWithDynamicLogLevel(
        string city, LogLevel level, string province);

    public void  TestLogging()
    {
        LogWithCustomEventName();

        LogWithDynamicLogLevel("Vancouver", LogLevel.Warning, "BC");
        LogWithDynamicLogLevel("Vancouver", LogLevel.Information, "BC");

        UsingFormatSpecifier(_logger, 12345.6789);
    }
}

 

The code that is generated is

// <auto-generated/>
#nullable enable

    partial class LoggingSample
    {
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.7.1805")]
        private static readonly global::System.Action<global::Microsoft.Extensions.Logging.ILogger, global::System.Double, global::System.Exception?> __UsingFormatSpecifierCallback =
            global::Microsoft.Extensions.Logging.LoggerMessage.Define<global::System.Double>(global::Microsoft.Extensions.Logging.LogLevel.Critical, new global::Microsoft.Extensions.Logging.EventId(20, nameof(UsingFormatSpecifier)), "Value is {value:E}", new global::Microsoft.Extensions.Logging.LogDefineOptions() { SkipEnabledCheck = true }); 

        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.7.1805")]
        public static partial void UsingFormatSpecifier(global::Microsoft.Extensions.Logging.ILogger logger, global::System.Double value)
        {
            if (logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Critical))
            {
                __UsingFormatSpecifierCallback(logger, value, null);
            }
        }
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.7.1805")]
        private static readonly global::System.Action<global::Microsoft.Extensions.Logging.ILogger, global::System.Exception?> __LogWithCustomEventNameCallback =
            global::Microsoft.Extensions.Logging.LoggerMessage.Define(global::Microsoft.Extensions.Logging.LogLevel.Trace, new global::Microsoft.Extensions.Logging.EventId(9, "CustomEventName"), "Fixed message", new global::Microsoft.Extensions.Logging.LogDefineOptions() { SkipEnabledCheck = true }); 

        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.7.1805")]
        public partial void LogWithCustomEventName()
        {
            if (_logger.IsEnabled(global::Microsoft.Extensions.Logging.LogLevel.Trace))
            {
                __LogWithCustomEventNameCallback(_logger, null);
            }
        }
        /// <summary> This API supports the logging infrastructure and is not intended to be used directly from your code. It is subject to change in the future. </summary>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.7.1805")]
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Never)]
        private readonly struct __LogWithDynamicLogLevelStruct : global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.KeyValuePair<string, object?>>
        {
            private readonly global::System.String _city;
            private readonly global::System.String _province;

            public __LogWithDynamicLogLevelStruct(global::System.String city, global::System.String province)
            {
                this._city = city;
                this._province = province;

            }

            public override string ToString()
            {
                var city = this._city;
                var province = this._province;

                return $"Welcome to {city} {province}!";
            }

            public static readonly global::System.Func<__LogWithDynamicLogLevelStruct, global::System.Exception?, string> Format = (state, ex) => state.ToString();

            public int Count => 3;

            public global::System.Collections.Generic.KeyValuePair<string, object?> this[int index]
            {
                get => index switch
                {
                    0 => new global::System.Collections.Generic.KeyValuePair<string, object?>("city", this._city),
                    1 => new global::System.Collections.Generic.KeyValuePair<string, object?>("province", this._province),
                    2 => new global::System.Collections.Generic.KeyValuePair<string, object?>("{OriginalFormat}", "Welcome to {city} {province}!"),

                    _ => throw new global::System.IndexOutOfRangeException(nameof(index)),  // return the same exception LoggerMessage.Define returns in this case
                };
            }

            public global::System.Collections.Generic.IEnumerator<global::System.Collections.Generic.KeyValuePair<string, object?>> GetEnumerator()
            {
                for (int i = 0; i < 3; i++)
                {
                    yield return this[i];
                }
            }

            global::System.Collections.IEnumerator global::System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
        }

        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "7.0.7.1805")]
        public partial void LogWithDynamicLogLevel(global::System.String city, global::Microsoft.Extensions.Logging.LogLevel level, global::System.String province)
        {
            if (_logger.IsEnabled(level))
            {
                _logger.Log(
                    level,
                    new global::Microsoft.Extensions.Logging.EventId(10, nameof(LogWithDynamicLogLevel)),
                    new __LogWithDynamicLogLevelStruct(city, province),
                    null,
                    __LogWithDynamicLogLevelStruct.Format);
            }
        }
    }

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Microsoft.Extensions.Logging

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.