Category: .NET Core

RSCG – MakeInterface.Generator

RSCG – MakeInterface.Generator
 
 

name MakeInterface.Generator
nuget https://www.nuget.org/packages/MakeInterface.Generator/
link https://github.com/Frederik91/MakeInterface
author Frederik

Generating interface from class definition

 

This is how you can use MakeInterface.Generator .

The code that you start with is


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

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

  <ItemGroup>
    <PackageReference Include="MakeInterface.Contracts" Version="0.4.0" />
    <PackageReference Include="MakeInterface.Generator" Version="0.4.0" OutputItemType="Analyzer" >
      <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://aka.ms/new-console-template for more information
using Class2Interface;

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


using MakeInterface.Contracts.Attributes;

namespace Class2Interface;
[GenerateInterface]
internal class Person:IPerson
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Name
    {
        get
        {
            return $"{FirstName} {LastName}";
        }
    }
    public string FullName()
    {
        return $"{FirstName} {LastName}";
    }
}


 

The code that is generated is

using MakeInterface.Contracts.Attributes;

// <auto-generated/>
#pragma warning disable
#nullable enable
namespace Class2Interface;
public partial interface IPerson
{
    int ID { get; set; }

    string FirstName { get; set; }

    string LastName { get; set; }

    string Name { get; }

    string FullName();
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/MakeInterface.Generator

RSCG – Funcky.DiscriminatedUnion

RSCG – Funcky.DiscriminatedUnion
 
 

name Funcky.DiscriminatedUnion
nuget https://www.nuget.org/packages/Funcky.DiscriminatedUnion/
link https://github.com/polyadic/funcky-discriminated-union
author Polyadic

Generating discriminated unions for C# 9.0 and above.

 

This is how you can use Funcky.DiscriminatedUnion .

The code that you start with is


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

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

  <ItemGroup>
    <PackageReference Include="Funcky.DiscriminatedUnion" Version="1.1.0"  />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using Union;

Console.WriteLine("Save or not");
var data = SaveToDatabase.Save(0);

Console.WriteLine(data.Match(ok => true, error => false));
data = SaveToDatabase.Save(1);
Console.WriteLine(data.Match(ok => true, error => false));



namespace Union;

[Funcky.DiscriminatedUnion]
public abstract partial record ResultSave
{
    public partial record Success(int Value): ResultSave;
    public partial record ValidationError(string Message):ResultSave;

    //public sealed partial record Ok(T Value) : ResultSave<T>;

    //public sealed partial record Error(Exception Exception) : ResultSave<T>;
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Union;
internal class SaveToDatabase
{
    public static ResultSave Save(int i)
    {
        if (i == 0)
        {
            return new ResultSave.ValidationError(" cannot save 0");
        }
        return new ResultSave.Success(i);
    }
}


 

The code that is generated is

// <auto-generated/>
#nullable enable

namespace Funcky
{
    [global::System.Diagnostics.Conditional("Funcky_DiscriminatedUnion")]
    [global::System.AttributeUsage(global::System.AttributeTargets.Class)]
    internal sealed class DiscriminatedUnionAttribute : global::System.Attribute
    {
        /// <summary>Allow only consumers in the same assembly to use the exhaustive <c>Match</c> and <c>Switch</c> methods.</summary>
        public bool NonExhaustive { get; set; }

        /// <summary>Generates exhaustive <c>Match</c> and <c>Switch</c> methods for the entire type hierarchy.</summary>
        public bool Flatten { get; set; }

        /// <summary>Customized the generic type name used for the result in the generated <c>Match</c> methods. Defaults to <c>TResult</c>.</summary>
        public string? MatchResultTypeName { get; set; }
    }
}

// <auto-generated/>
#nullable enable

namespace Union
{
    partial record ResultSave
    {
        [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")]
        public abstract TResult Match<TResult>(global::System.Func<Success, TResult> success, global::System.Func<ValidationError, TResult> validationError);
        
        [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")]
        public abstract void Switch(global::System.Action<Success> success, global::System.Action<ValidationError> validationError);
        
        partial record Success
        {
            [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")]
            public override TResult Match<TResult>(global::System.Func<Success, TResult> success, global::System.Func<ValidationError, TResult> validationError) => success(this);
            
            [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")]
            public override void Switch(global::System.Action<Success> success, global::System.Action<ValidationError> validationError) => success(this);
        }
        
        partial record ValidationError
        {
            [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")]
            public override TResult Match<TResult>(global::System.Func<Success, TResult> success, global::System.Func<ValidationError, TResult> validationError) => validationError(this);
            
            [global::System.CodeDom.Compiler.GeneratedCode("Funcky.DiscriminatedUnion.SourceGeneration", "1.1.0.0")]
            public override void Switch(global::System.Action<Success> success, global::System.Action<ValidationError> validationError) => validationError(this);
        }
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Funcky.DiscriminatedUnion

RSCG – DomainPrimitives

RSCG – DomainPrimitives
 
 

name DomainPrimitives
nuget https://www.nuget.org/packages/AltaSoft.DomainPrimitives.Generator
https://www.nuget.org/packages/AltaSoft.DomainPrimitives.Abstractions
link https://github.com/altasoft/DomainPrimitives
author Alta Software – Teimuraz Nikolaishvili

One of the most complete and mature libraries for DomainPrimitives in .NET

 

This is how you can use DomainPrimitives .

The code that you start with is


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

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

	<ItemGroup>
		<PackageReference Include="AltaSoft.DomainPrimitives.Abstractions" Version="1.0.3" />
		<PackageReference Include="AltaSoft.DomainPrimitives.Generator" Version="1.0.3" OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="all" ExcludeAssets="runtime" />
	</ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

	<PropertyGroup>
		<!--<DomainPrimitiveGenerator_GenerateJsonConverters>false</DomainPrimitiveGenerator_GenerateJsonConverters>-->
		<!--<DomainPrimitiveGenerator_GenerateTypeConverters>false</DomainPrimitiveGenerator_GenerateTypeConverters>-->
		<DomainPrimitiveGenerator_GenerateSwaggerConverters>false</DomainPrimitiveGenerator_GenerateSwaggerConverters>
	</PropertyGroup>
	<ItemGroup>
		<!--<CompilerVisibleProperty Include="DomainPrimitiveGenerator_GenerateTypeConverters" />-->
		<!--<CompilerVisibleProperty Include="DomainPrimitiveGenerator_GenerateJsonConverters" />-->
		<CompilerVisibleProperty Include="DomainPrimitiveGenerator_GenerateSwaggerConverters" />
	</ItemGroup>

</Project>


The code that you will use is


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

var year = new YearDate(1970);
var month = new MonthDate(4);
var day = new DayDate(16);
year += 1;
var p=new Person(year,month,day);

Console.WriteLine(p.DOB);


using AltaSoft.DomainPrimitives.Abstractions;

namespace DomainPrimitives;

public readonly partial record struct YearDate : IDomainValue<int>
{
    public static void Validate(int value)
    {
        if (value <= 0)
            throw new InvalidDomainValueException("year must be positive");
    }
    public static int Default => 1;
}
public readonly partial record struct MonthDate : IDomainValue<int>
{
    public static void Validate(int value)
    {
        if (value <= 0)
            throw new InvalidDomainValueException("year must be positive");
    }
    public static int Default => 1;
}

public readonly partial record struct DayDate : IDomainValue<int>
{
    public static void Validate(int value)
    {
        if (value <= 0)
            throw new InvalidDomainValueException("year must be positive");
    }
    public static int Default => 1;
}



namespace DomainPrimitives;
internal class Person
{
    public Person(YearDate year,MonthDate month,DayDate day)
    {
        DOB = new DateOnly(year,month,day);
    }
    public DateOnly DOB { get; private set; }

    
}


 

The code that is generated is

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a AltaSoft.DomainPrimitives.Generator v1.0.0
//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

using System;
using System.Numerics;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using DomainPrimitives.Converters;
using System.ComponentModel;

namespace DomainPrimitives;

[JsonConverter(typeof(DayDateJsonConverter))]
[TypeConverter(typeof(DayDateTypeConverter))]
[DebuggerDisplay("{_valueOrDefault}")]
public readonly partial record struct DayDate :
		IAdditionOperators<DayDate, DayDate, DayDate>,
		ISubtractionOperators<DayDate, DayDate, DayDate>,
		IMultiplyOperators<DayDate, DayDate, DayDate>,
		IDivisionOperators<DayDate, DayDate, DayDate>,
		IModulusOperators<DayDate, DayDate, DayDate>,
		IComparisonOperators<DayDate, DayDate, bool>,
		IComparable,
		IComparable<DayDate>,
		IParsable<DayDate>,
		IConvertible
{
	private int _valueOrDefault => _isInitialized ? _value : Default;
	[DebuggerBrowsable(DebuggerBrowsableState.Never)]
	private readonly int _value;
	[DebuggerBrowsable(DebuggerBrowsableState.Never)]
	private readonly bool _isInitialized;
	
	/// <summary>
	/// Initializes a new instance of the <see cref="DayDate"/> class by validating the specified <see cref="int"/> value using <see cref="Validate"/> static method.
	/// </summary>
	/// <param name="value">The value to be validated..</param>
	public DayDate(int value)
	{
			Validate(value);
			_value = value;
			_isInitialized = true;
	}
	
	[Obsolete("Domain primitive cannot be created using empty Ctor", true)]
	public DayDate() : this(Default)
	{
	}
	
	/// <summary>
	/// <summary>Implicit conversion from <see cref = "int"/> to <see cref = "DayDate"/></summary>
	/// </summary>
	public static implicit operator DayDate(int value) => new(value);

	/// <summary>
	/// <summary>Implicit conversion from <see cref = "int?"/> to <see cref = "DayDate?"/></summary>
	/// </summary>
	[return: NotNullIfNotNull(nameof(value))]
	public static implicit operator DayDate?(int? value) => value is null ? null : new(value.Value);

	/// <summary>
	/// <summary>Implicit conversion from <see cref = "DayDate"/> to <see cref = "int"/></summary>
	/// </summary>
	public static implicit operator int(DayDate value) => (int)value._valueOrDefault;

	/// <inheritdoc/>
	public static DayDate operator +(DayDate left, DayDate right) => new(left._valueOrDefault + right._valueOrDefault);

	/// <inheritdoc/>
	public static DayDate operator -(DayDate left, DayDate right) => new(left._valueOrDefault - right._valueOrDefault);

	/// <inheritdoc/>
	public static DayDate operator *(DayDate left, DayDate right) => new(left._valueOrDefault * right._valueOrDefault);

	/// <inheritdoc/>
	public static DayDate operator /(DayDate left, DayDate right) => new(left._valueOrDefault / right._valueOrDefault);

	/// <inheritdoc/>
	public static DayDate operator %(DayDate left, DayDate right) => new(left._valueOrDefault % right._valueOrDefault);

	/// <inheritdoc/>
	public int CompareTo(object? value)
	{
		if (value is null)
			return 1;

		if (value is DayDate c)
			return CompareTo(c);

		throw new ArgumentException("Object is not a DayDate", nameof(value));
	}

	/// <inheritdoc/>
	public int CompareTo(DayDate other) => _valueOrDefault.CompareTo(other._valueOrDefault);

	/// <inheritdoc/>
	public static bool operator <(DayDate left, DayDate right) => left._valueOrDefault < right._valueOrDefault;

	/// <inheritdoc/>
	public static bool operator <=(DayDate left, DayDate right) => left._valueOrDefault <= right._valueOrDefault;

	/// <inheritdoc/>
	public static bool operator >(DayDate left, DayDate right) => left._valueOrDefault > right._valueOrDefault;

	/// <inheritdoc/>
	public static bool operator >=(DayDate left, DayDate right) => left._valueOrDefault >= right._valueOrDefault;


	/// <inheritdoc/>
	public static DayDate Parse(string s, IFormatProvider? provider) => int.Parse(s, provider);

	/// <inheritdoc/>
	public static bool TryParse(string? s, IFormatProvider? provider, out DayDate result)
	{
		if (int.TryParse(s, provider, out var value))
		{
			result = new DayDate(value);
			return true;
		}
		result = default;
		return false;
	}


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

	/// <inheritdoc/>
	TypeCode IConvertible.GetTypeCode() => ((IConvertible)_valueOrDefault).GetTypeCode();

	/// <inheritdoc/>
	bool IConvertible.ToBoolean(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToBoolean(provider);

	/// <inheritdoc/>
	byte IConvertible.ToByte(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToByte(provider);

	/// <inheritdoc/>
	char IConvertible.ToChar(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToChar(provider);

	/// <inheritdoc/>
	DateTime IConvertible.ToDateTime(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToDateTime(provider);

	/// <inheritdoc/>
	decimal IConvertible.ToDecimal(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToDecimal(provider);

	/// <inheritdoc/>
	double IConvertible.ToDouble(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToDouble(provider);

	/// <inheritdoc/>
	short IConvertible.ToInt16(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToInt16(provider);

	/// <inheritdoc/>
	int IConvertible.ToInt32(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToInt32(provider);

	/// <inheritdoc/>
	long IConvertible.ToInt64(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToInt64(provider);

	/// <inheritdoc/>
	sbyte IConvertible.ToSByte(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToSByte(provider);

	/// <inheritdoc/>
	float IConvertible.ToSingle(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToSingle(provider);

	/// <inheritdoc/>
	string IConvertible.ToString(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToString(provider);

	/// <inheritdoc/>
	object IConvertible.ToType(Type conversionType, IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToType(conversionType, provider);

	/// <inheritdoc/>
	ushort IConvertible.ToUInt16(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToUInt16(provider);

	/// <inheritdoc/>
	uint IConvertible.ToUInt32(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToUInt32(provider);

	/// <inheritdoc/>
	ulong IConvertible.ToUInt64(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToUInt64(provider);
}

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a AltaSoft.DomainPrimitives.Generator v1.0.0
//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

using DomainPrimitives;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Globalization;
using System.Text.Json.Serialization.Metadata;
using AltaSoft.DomainPrimitives.Abstractions;

namespace DomainPrimitives.Converters;

/// <summary>
/// JsonConverter for <see cref = "DayDate"/>
/// </summary>
public sealed class DayDateJsonConverter : JsonConverter<DayDate>
{
	/// <inheritdoc/>
	public override DayDate Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
	{
		try
		{
			return JsonInternalConverters.Int32Converter.Read(ref reader, typeToConvert, options);
		}
		catch (InvalidDomainValueException ex)
		{
			throw new JsonException(ex.Message);
		}
	}

	/// <inheritdoc/>
	public override void Write(Utf8JsonWriter writer, DayDate value, JsonSerializerOptions options)
	{
		JsonInternalConverters.Int32Converter.Write(writer, (int)value, options);
	}

	/// <inheritdoc/>
	public override DayDate ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
	{
		try
		{
			return JsonInternalConverters.Int32Converter.ReadAsPropertyName(ref reader, typeToConvert, options);
		}
		catch (InvalidDomainValueException ex)
		{
			throw new JsonException(ex.Message);
		}
	}

	/// <inheritdoc/>
	public override void WriteAsPropertyName(Utf8JsonWriter writer, DayDate value, JsonSerializerOptions options)
	{
		JsonInternalConverters.Int32Converter.WriteAsPropertyName(writer, (int)value, options);
	}
}

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a AltaSoft.DomainPrimitives.Generator v1.0.0
//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

using DomainPrimitives;
using System;
using System.ComponentModel;
using System.Globalization;
using AltaSoft.DomainPrimitives.Abstractions;

namespace DomainPrimitives.Converters;

/// <summary>
/// TypeConverter for <see cref = "DayDate"/>
/// </summary>
public sealed class DayDateTypeConverter : Int32Converter
{
	/// <inheritdoc/>
	public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
	{
		var result = base.ConvertFrom(context, culture, value);
		if (result is null)
			return null;
		try
		{
			return new DayDate((int)result);
		}
		catch (InvalidDomainValueException ex)
		{
			throw new FormatException("Cannot parse DayDate", ex);
		}
	}
}

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a AltaSoft.DomainPrimitives.Generator v1.0.0
//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

using System;
using System.Numerics;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using DomainPrimitives.Converters;
using System.ComponentModel;

namespace DomainPrimitives;

[JsonConverter(typeof(MonthDateJsonConverter))]
[TypeConverter(typeof(MonthDateTypeConverter))]
[DebuggerDisplay("{_valueOrDefault}")]
public readonly partial record struct MonthDate :
		IAdditionOperators<MonthDate, MonthDate, MonthDate>,
		ISubtractionOperators<MonthDate, MonthDate, MonthDate>,
		IMultiplyOperators<MonthDate, MonthDate, MonthDate>,
		IDivisionOperators<MonthDate, MonthDate, MonthDate>,
		IModulusOperators<MonthDate, MonthDate, MonthDate>,
		IComparisonOperators<MonthDate, MonthDate, bool>,
		IComparable,
		IComparable<MonthDate>,
		IParsable<MonthDate>,
		IConvertible
{
	private int _valueOrDefault => _isInitialized ? _value : Default;
	[DebuggerBrowsable(DebuggerBrowsableState.Never)]
	private readonly int _value;
	[DebuggerBrowsable(DebuggerBrowsableState.Never)]
	private readonly bool _isInitialized;
	
	/// <summary>
	/// Initializes a new instance of the <see cref="MonthDate"/> class by validating the specified <see cref="int"/> value using <see cref="Validate"/> static method.
	/// </summary>
	/// <param name="value">The value to be validated..</param>
	public MonthDate(int value)
	{
			Validate(value);
			_value = value;
			_isInitialized = true;
	}
	
	[Obsolete("Domain primitive cannot be created using empty Ctor", true)]
	public MonthDate() : this(Default)
	{
	}
	
	/// <summary>
	/// <summary>Implicit conversion from <see cref = "int"/> to <see cref = "MonthDate"/></summary>
	/// </summary>
	public static implicit operator MonthDate(int value) => new(value);

	/// <summary>
	/// <summary>Implicit conversion from <see cref = "int?"/> to <see cref = "MonthDate?"/></summary>
	/// </summary>
	[return: NotNullIfNotNull(nameof(value))]
	public static implicit operator MonthDate?(int? value) => value is null ? null : new(value.Value);

	/// <summary>
	/// <summary>Implicit conversion from <see cref = "MonthDate"/> to <see cref = "int"/></summary>
	/// </summary>
	public static implicit operator int(MonthDate value) => (int)value._valueOrDefault;

	/// <inheritdoc/>
	public static MonthDate operator +(MonthDate left, MonthDate right) => new(left._valueOrDefault + right._valueOrDefault);

	/// <inheritdoc/>
	public static MonthDate operator -(MonthDate left, MonthDate right) => new(left._valueOrDefault - right._valueOrDefault);

	/// <inheritdoc/>
	public static MonthDate operator *(MonthDate left, MonthDate right) => new(left._valueOrDefault * right._valueOrDefault);

	/// <inheritdoc/>
	public static MonthDate operator /(MonthDate left, MonthDate right) => new(left._valueOrDefault / right._valueOrDefault);

	/// <inheritdoc/>
	public static MonthDate operator %(MonthDate left, MonthDate right) => new(left._valueOrDefault % right._valueOrDefault);

	/// <inheritdoc/>
	public int CompareTo(object? value)
	{
		if (value is null)
			return 1;

		if (value is MonthDate c)
			return CompareTo(c);

		throw new ArgumentException("Object is not a MonthDate", nameof(value));
	}

	/// <inheritdoc/>
	public int CompareTo(MonthDate other) => _valueOrDefault.CompareTo(other._valueOrDefault);

	/// <inheritdoc/>
	public static bool operator <(MonthDate left, MonthDate right) => left._valueOrDefault < right._valueOrDefault;

	/// <inheritdoc/>
	public static bool operator <=(MonthDate left, MonthDate right) => left._valueOrDefault <= right._valueOrDefault;

	/// <inheritdoc/>
	public static bool operator >(MonthDate left, MonthDate right) => left._valueOrDefault > right._valueOrDefault;

	/// <inheritdoc/>
	public static bool operator >=(MonthDate left, MonthDate right) => left._valueOrDefault >= right._valueOrDefault;


	/// <inheritdoc/>
	public static MonthDate Parse(string s, IFormatProvider? provider) => int.Parse(s, provider);

	/// <inheritdoc/>
	public static bool TryParse(string? s, IFormatProvider? provider, out MonthDate result)
	{
		if (int.TryParse(s, provider, out var value))
		{
			result = new MonthDate(value);
			return true;
		}
		result = default;
		return false;
	}


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

	/// <inheritdoc/>
	TypeCode IConvertible.GetTypeCode() => ((IConvertible)_valueOrDefault).GetTypeCode();

	/// <inheritdoc/>
	bool IConvertible.ToBoolean(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToBoolean(provider);

	/// <inheritdoc/>
	byte IConvertible.ToByte(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToByte(provider);

	/// <inheritdoc/>
	char IConvertible.ToChar(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToChar(provider);

	/// <inheritdoc/>
	DateTime IConvertible.ToDateTime(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToDateTime(provider);

	/// <inheritdoc/>
	decimal IConvertible.ToDecimal(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToDecimal(provider);

	/// <inheritdoc/>
	double IConvertible.ToDouble(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToDouble(provider);

	/// <inheritdoc/>
	short IConvertible.ToInt16(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToInt16(provider);

	/// <inheritdoc/>
	int IConvertible.ToInt32(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToInt32(provider);

	/// <inheritdoc/>
	long IConvertible.ToInt64(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToInt64(provider);

	/// <inheritdoc/>
	sbyte IConvertible.ToSByte(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToSByte(provider);

	/// <inheritdoc/>
	float IConvertible.ToSingle(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToSingle(provider);

	/// <inheritdoc/>
	string IConvertible.ToString(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToString(provider);

	/// <inheritdoc/>
	object IConvertible.ToType(Type conversionType, IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToType(conversionType, provider);

	/// <inheritdoc/>
	ushort IConvertible.ToUInt16(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToUInt16(provider);

	/// <inheritdoc/>
	uint IConvertible.ToUInt32(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToUInt32(provider);

	/// <inheritdoc/>
	ulong IConvertible.ToUInt64(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToUInt64(provider);
}

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a AltaSoft.DomainPrimitives.Generator v1.0.0
//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

using DomainPrimitives;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Globalization;
using System.Text.Json.Serialization.Metadata;
using AltaSoft.DomainPrimitives.Abstractions;

namespace DomainPrimitives.Converters;

/// <summary>
/// JsonConverter for <see cref = "MonthDate"/>
/// </summary>
public sealed class MonthDateJsonConverter : JsonConverter<MonthDate>
{
	/// <inheritdoc/>
	public override MonthDate Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
	{
		try
		{
			return JsonInternalConverters.Int32Converter.Read(ref reader, typeToConvert, options);
		}
		catch (InvalidDomainValueException ex)
		{
			throw new JsonException(ex.Message);
		}
	}

	/// <inheritdoc/>
	public override void Write(Utf8JsonWriter writer, MonthDate value, JsonSerializerOptions options)
	{
		JsonInternalConverters.Int32Converter.Write(writer, (int)value, options);
	}

	/// <inheritdoc/>
	public override MonthDate ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
	{
		try
		{
			return JsonInternalConverters.Int32Converter.ReadAsPropertyName(ref reader, typeToConvert, options);
		}
		catch (InvalidDomainValueException ex)
		{
			throw new JsonException(ex.Message);
		}
	}

	/// <inheritdoc/>
	public override void WriteAsPropertyName(Utf8JsonWriter writer, MonthDate value, JsonSerializerOptions options)
	{
		JsonInternalConverters.Int32Converter.WriteAsPropertyName(writer, (int)value, options);
	}
}

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a AltaSoft.DomainPrimitives.Generator v1.0.0
//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

using DomainPrimitives;
using System;
using System.ComponentModel;
using System.Globalization;
using AltaSoft.DomainPrimitives.Abstractions;

namespace DomainPrimitives.Converters;

/// <summary>
/// TypeConverter for <see cref = "MonthDate"/>
/// </summary>
public sealed class MonthDateTypeConverter : Int32Converter
{
	/// <inheritdoc/>
	public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
	{
		var result = base.ConvertFrom(context, culture, value);
		if (result is null)
			return null;
		try
		{
			return new MonthDate((int)result);
		}
		catch (InvalidDomainValueException ex)
		{
			throw new FormatException("Cannot parse MonthDate", ex);
		}
	}
}

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a AltaSoft.DomainPrimitives.Generator v1.0.0
//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

using System;
using System.Numerics;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using DomainPrimitives.Converters;
using System.ComponentModel;

namespace DomainPrimitives;

[JsonConverter(typeof(YearDateJsonConverter))]
[TypeConverter(typeof(YearDateTypeConverter))]
[DebuggerDisplay("{_valueOrDefault}")]
public readonly partial record struct YearDate :
		IAdditionOperators<YearDate, YearDate, YearDate>,
		ISubtractionOperators<YearDate, YearDate, YearDate>,
		IMultiplyOperators<YearDate, YearDate, YearDate>,
		IDivisionOperators<YearDate, YearDate, YearDate>,
		IModulusOperators<YearDate, YearDate, YearDate>,
		IComparisonOperators<YearDate, YearDate, bool>,
		IComparable,
		IComparable<YearDate>,
		IParsable<YearDate>,
		IConvertible
{
	private int _valueOrDefault => _isInitialized ? _value : Default;
	[DebuggerBrowsable(DebuggerBrowsableState.Never)]
	private readonly int _value;
	[DebuggerBrowsable(DebuggerBrowsableState.Never)]
	private readonly bool _isInitialized;
	
	/// <summary>
	/// Initializes a new instance of the <see cref="YearDate"/> class by validating the specified <see cref="int"/> value using <see cref="Validate"/> static method.
	/// </summary>
	/// <param name="value">The value to be validated..</param>
	public YearDate(int value)
	{
			Validate(value);
			_value = value;
			_isInitialized = true;
	}
	
	[Obsolete("Domain primitive cannot be created using empty Ctor", true)]
	public YearDate() : this(Default)
	{
	}
	
	/// <summary>
	/// <summary>Implicit conversion from <see cref = "int"/> to <see cref = "YearDate"/></summary>
	/// </summary>
	public static implicit operator YearDate(int value) => new(value);

	/// <summary>
	/// <summary>Implicit conversion from <see cref = "int?"/> to <see cref = "YearDate?"/></summary>
	/// </summary>
	[return: NotNullIfNotNull(nameof(value))]
	public static implicit operator YearDate?(int? value) => value is null ? null : new(value.Value);

	/// <summary>
	/// <summary>Implicit conversion from <see cref = "YearDate"/> to <see cref = "int"/></summary>
	/// </summary>
	public static implicit operator int(YearDate value) => (int)value._valueOrDefault;

	/// <inheritdoc/>
	public static YearDate operator +(YearDate left, YearDate right) => new(left._valueOrDefault + right._valueOrDefault);

	/// <inheritdoc/>
	public static YearDate operator -(YearDate left, YearDate right) => new(left._valueOrDefault - right._valueOrDefault);

	/// <inheritdoc/>
	public static YearDate operator *(YearDate left, YearDate right) => new(left._valueOrDefault * right._valueOrDefault);

	/// <inheritdoc/>
	public static YearDate operator /(YearDate left, YearDate right) => new(left._valueOrDefault / right._valueOrDefault);

	/// <inheritdoc/>
	public static YearDate operator %(YearDate left, YearDate right) => new(left._valueOrDefault % right._valueOrDefault);

	/// <inheritdoc/>
	public int CompareTo(object? value)
	{
		if (value is null)
			return 1;

		if (value is YearDate c)
			return CompareTo(c);

		throw new ArgumentException("Object is not a YearDate", nameof(value));
	}

	/// <inheritdoc/>
	public int CompareTo(YearDate other) => _valueOrDefault.CompareTo(other._valueOrDefault);

	/// <inheritdoc/>
	public static bool operator <(YearDate left, YearDate right) => left._valueOrDefault < right._valueOrDefault;

	/// <inheritdoc/>
	public static bool operator <=(YearDate left, YearDate right) => left._valueOrDefault <= right._valueOrDefault;

	/// <inheritdoc/>
	public static bool operator >(YearDate left, YearDate right) => left._valueOrDefault > right._valueOrDefault;

	/// <inheritdoc/>
	public static bool operator >=(YearDate left, YearDate right) => left._valueOrDefault >= right._valueOrDefault;


	/// <inheritdoc/>
	public static YearDate Parse(string s, IFormatProvider? provider) => int.Parse(s, provider);

	/// <inheritdoc/>
	public static bool TryParse(string? s, IFormatProvider? provider, out YearDate result)
	{
		if (int.TryParse(s, provider, out var value))
		{
			result = new YearDate(value);
			return true;
		}
		result = default;
		return false;
	}


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

	/// <inheritdoc/>
	TypeCode IConvertible.GetTypeCode() => ((IConvertible)_valueOrDefault).GetTypeCode();

	/// <inheritdoc/>
	bool IConvertible.ToBoolean(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToBoolean(provider);

	/// <inheritdoc/>
	byte IConvertible.ToByte(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToByte(provider);

	/// <inheritdoc/>
	char IConvertible.ToChar(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToChar(provider);

	/// <inheritdoc/>
	DateTime IConvertible.ToDateTime(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToDateTime(provider);

	/// <inheritdoc/>
	decimal IConvertible.ToDecimal(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToDecimal(provider);

	/// <inheritdoc/>
	double IConvertible.ToDouble(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToDouble(provider);

	/// <inheritdoc/>
	short IConvertible.ToInt16(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToInt16(provider);

	/// <inheritdoc/>
	int IConvertible.ToInt32(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToInt32(provider);

	/// <inheritdoc/>
	long IConvertible.ToInt64(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToInt64(provider);

	/// <inheritdoc/>
	sbyte IConvertible.ToSByte(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToSByte(provider);

	/// <inheritdoc/>
	float IConvertible.ToSingle(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToSingle(provider);

	/// <inheritdoc/>
	string IConvertible.ToString(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToString(provider);

	/// <inheritdoc/>
	object IConvertible.ToType(Type conversionType, IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToType(conversionType, provider);

	/// <inheritdoc/>
	ushort IConvertible.ToUInt16(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToUInt16(provider);

	/// <inheritdoc/>
	uint IConvertible.ToUInt32(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToUInt32(provider);

	/// <inheritdoc/>
	ulong IConvertible.ToUInt64(IFormatProvider? provider) => ((IConvertible)_valueOrDefault).ToUInt64(provider);
}

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a AltaSoft.DomainPrimitives.Generator v1.0.0
//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

using DomainPrimitives;
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Globalization;
using System.Text.Json.Serialization.Metadata;
using AltaSoft.DomainPrimitives.Abstractions;

namespace DomainPrimitives.Converters;

/// <summary>
/// JsonConverter for <see cref = "YearDate"/>
/// </summary>
public sealed class YearDateJsonConverter : JsonConverter<YearDate>
{
	/// <inheritdoc/>
	public override YearDate Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
	{
		try
		{
			return JsonInternalConverters.Int32Converter.Read(ref reader, typeToConvert, options);
		}
		catch (InvalidDomainValueException ex)
		{
			throw new JsonException(ex.Message);
		}
	}

	/// <inheritdoc/>
	public override void Write(Utf8JsonWriter writer, YearDate value, JsonSerializerOptions options)
	{
		JsonInternalConverters.Int32Converter.Write(writer, (int)value, options);
	}

	/// <inheritdoc/>
	public override YearDate ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
	{
		try
		{
			return JsonInternalConverters.Int32Converter.ReadAsPropertyName(ref reader, typeToConvert, options);
		}
		catch (InvalidDomainValueException ex)
		{
			throw new JsonException(ex.Message);
		}
	}

	/// <inheritdoc/>
	public override void WriteAsPropertyName(Utf8JsonWriter writer, YearDate value, JsonSerializerOptions options)
	{
		JsonInternalConverters.Int32Converter.WriteAsPropertyName(writer, (int)value, options);
	}
}

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a AltaSoft.DomainPrimitives.Generator v1.0.0
//     Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#nullable enable

using DomainPrimitives;
using System;
using System.ComponentModel;
using System.Globalization;
using AltaSoft.DomainPrimitives.Abstractions;

namespace DomainPrimitives.Converters;

/// <summary>
/// TypeConverter for <see cref = "YearDate"/>
/// </summary>
public sealed class YearDateTypeConverter : Int32Converter
{
	/// <inheritdoc/>
	public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
	{
		var result = base.ConvertFrom(context, culture, value);
		if (result is null)
			return null;
		try
		{
			return new YearDate((int)result);
		}
		catch (InvalidDomainValueException ex)
		{
			throw new FormatException("Cannot parse YearDate", ex);
		}
	}
}

Code and pdf at

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

RSCG – HsuSgSync

RSCG – HsuSgSync
 
 

name HsuSgSync
nuget https://www.nuget.org/packages/Hsu.Sg.Sync/
link https://github.com/hsu-net/source-generators
author Net Hsu

Generate code for async to sync methods

 

This is how you can use HsuSgSync .

The code that you start with is


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

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

  <ItemGroup>
    <PackageReference Include="Hsu.Sg.Sync" Version="2023.412.21" OutputItemType="Analyzer" >
    </PackageReference>
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using HsuSgSync;

var p=new Person();
var result=await p.RunAsync();
Console.WriteLine(result);
result=p.Run();



using System.ComponentModel;
using Hsu.Sg.Sync;
namespace HsuSgSync;
[Sync]
internal partial class Person
{   
    public async Task<bool> RunAsync()
    {
        await Task.Delay(1000);
        return true;
    }
}


 

The code that is generated is

// <auto-generated/>

using System;

namespace Hsu.Sg.Sync
{
    /// <summary>
    /// The flag to generate async method to sync method.
    /// </summary>
    [AttributeUsage(
        System.AttributeTargets.Interface |
        System.AttributeTargets.Struct |
        System.AttributeTargets.Class,
        AllowMultiple = false,
        Inherited = false)]
    internal sealed class SyncAttribute : Attribute
    {
        /// <summary>
        ///     Only <c>interface</c> or <c>abstract</c> async methods are generated.
        /// </summary>
        public bool Definable { get; set; }
        
        /// <summary>
        /// The public async methods are generated.
        /// </summary>
        public bool Public { get; set; } = true;

        /// <summary>
        /// The internal async methods are generated.
        /// </summary>
        public bool Internal { get; set; } = true;

        /// <summary>
        /// The private async methods are generated.
        /// </summary>
        public bool Private { get; set; } = true;

        /// <summary>
        /// Only [SyncGen] async methods are generated.
        /// </summary>
        public bool Only { get; set; } = false;

        /// <summary>
        /// The suffix of sync method name when not end with Async.
        /// </summary>
        /// <remarks>default is `Sync`</remarks>
        public string Suffix { get; set; } = string.Empty;

        /// <summary>
        /// Whether generate attributes.
        /// </summary>
        public bool Attribute { get; set; } = false;

        /// <summary>
        /// To generate with attributes
        /// </summary>
        public string[] AttributeIncludes { get; set; } = null;

        /// <summary>
        /// To generate without attributes
        /// </summary>
        public string[] AttributeExcludes { get; set; } = null;

        public SyncAttribute()
        {
            Public = true;
            Internal = true;
            Private = true;
            Only = false;
            Suffix = string.Empty;
        }
    }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    internal sealed class SyncGenAttribute : Attribute
    {
        /// <summary>
        /// Ignore to generate sync methods. 
        /// </summary>
        public bool Ignore { get; set; } = false;
        
        /// <summary>
        /// The specific name of sync method.
        /// </summary>
        public string Identifier { get; set; } = string.Empty;

        /// <summary>
        /// The suffix of sync method name when not end with Async.
        /// </summary>
        /// <remarks>default is `Sync`</remarks>
        public string Suffix { get; set; } = string.Empty;
    }
}
// <auto-generated/>

using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System;

namespace Hsu.Sg.Sync
{
    internal static partial class SyncHelper
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Run(Task task)
        {
            Nito.AsyncEx.AsyncContext.Run(async () => await task);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static T Run<T>(Task<T> task)
        {
            return Nito.AsyncEx.AsyncContext.Run(async () => await task);
        }
        
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Run(Func<Task> task)
        {
            Nito.AsyncEx.AsyncContext.Run(async () => await task());
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static T Run<T>(Func<Task<T>> task)
        {
            return Nito.AsyncEx.AsyncContext.Run(async () => await task());
        }
    }
}
// <auto-generated/>

using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System;

namespace Hsu.Sg.Sync
{
    internal static partial class SyncHelper
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Run(ValueTask task)
        {
            Nito.AsyncEx.AsyncContext.Run(async () => await task);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static T Run<T>(ValueTask<T> task)
        {
            return Nito.AsyncEx.AsyncContext.Run(async () => await task);
        }
        
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void Run(Func<ValueTask> task)
        {
            Nito.AsyncEx.AsyncContext.Run(async () => await task());
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static T Run<T>(Func<ValueTask<T>> task)
        {
            return Nito.AsyncEx.AsyncContext.Run(async () => await task());
        }
    }
}
// <auto-generated/>
// Generated 1 sync methods by SyncGenerator
// ValueTaskSupported : True
// DefaultImplementationsOfInterfacesSupported : True
// Metadata { Only = False, Definable = False, Public = True, Internal = True, Private = True, Attribute = False  }

using System.ComponentModel;

namespace HsuSgSync;

internal partial class Person
{
    /// <inheritdoc cref="RunAsync()" />
    /// <remarks></remarks>
    public bool Run() 
    	=> Hsu.Sg.Sync.SyncHelper.Run(() => RunAsync());
}

Code and pdf at

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

RSCG – CopyCat

RSCG – CopyCat
 
 

name CopyCat
nuget https://www.nuget.org/packages/Copycat/
link https://github.com/Otaman/Copycat/
author Serhii Buta

Implementation of the Decorator pattern in C# – only for not implemented methods

 

This is how you can use CopyCat .

The code that you start with is


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

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

  <ItemGroup>
    <PackageReference Include="Copycat" Version="0.2.0-beta.1" OutputItemType="Analyzer"   />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using CCDemo;

ICoffee c =new Coffee();
c= new CoffeeWithLogging(c);
await c.Prepare();



namespace CCDemo;

internal interface ICoffee
{
    //for the moment does not work for properties in interface
    //string? Name { get; set; }
    Task<bool> Prepare();

    string[] GetIngredients();
}


namespace CCDemo;
internal class Coffee : ICoffee
{
    public string? Name { get; set; }
    public async Task<bool> Prepare()
    {
        Console.WriteLine("start prepare coffee");
        await Task.Delay(1000);
        Console.WriteLine("finish prepare coffee");
        return true;
    }
    public string[] GetIngredients() => new[] { "water", "coffee" };

}



using Copycat;

namespace CCDemo;
[Decorate]
internal partial class CoffeeWithLogging: ICoffee
{
    [Template]
    private string[] AddLogging(Func<string[]> action)
    {
        try
        {
            Console.WriteLine($"start logging {nameof(action)}  ");
            return action();
        }
        catch (Exception e)
        {
            Console.WriteLine($"exception  {nameof(action)} ");
            throw;
        }
        finally
        {
               Console.WriteLine($"end logging {nameof(action)} ");
        }
    }


    [Template]
    public async Task<bool> AddLogging(Func<Task<bool>> action)       
    {
        try
        {
            Console.WriteLine($"start logging {nameof(action)} ");
            return await action();
        }
        catch (Exception e)
        {
            Console.WriteLine($"exception  {nameof(action)} ");
            throw;
        }
        finally
        {
            Console.WriteLine($"end logging {nameof(action)} ");
        }
    }
}


 

The code that is generated is

// <auto-generated/>
using Copycat;

namespace CCDemo;
internal partial class CoffeeWithLogging
{
    private CCDemo.ICoffee _decorated;
    public CoffeeWithLogging(CCDemo.ICoffee decorated)
    {
        _decorated = decorated;
    }

    /// <see cref = "CoffeeWithLogging.AddLogging(Func{Task{bool}})"/>
    public async //for the moment does not work for properties in interface
    //string? Name { get; set; }
    Task<bool> Prepare()
    {
        try
        {
            Console.WriteLine($"start logging {nameof(Prepare)} ");
            return await _decorated.Prepare();
        }
        catch (Exception e)
        {
            Console.WriteLine($"exception  {nameof(Prepare)} ");
            throw;
        }
        finally
        {
            Console.WriteLine($"end logging {nameof(Prepare)} ");
        }
    }

    /// <see cref = "CoffeeWithLogging.AddLogging(Func{string[]})"/>
    public string[] GetIngredients()
    {
        try
        {
            Console.WriteLine($"start logging {nameof(GetIngredients)}  ");
            return _decorated.GetIngredients();
        }
        catch (Exception e)
        {
            Console.WriteLine($"exception  {nameof(GetIngredients)} ");
            throw;
        }
        finally
        {
            Console.WriteLine($"end logging {nameof(GetIngredients)} ");
        }
    }
}

Code and pdf at

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

RSCG – AspectGenerator

RSCG – AspectGenerator
 
 

name AspectGenerator
nuget https://www.nuget.org/packages/AspectGenerator/
link https://github.com/igor-tkachev/AspectGenerator
author Igor Tkachev

AOP for methods in the same project. Uses interceptors

 

This is how you can use AspectGenerator .

The code that you start with is


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

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

  <ItemGroup>
    <PackageReference Include="AspectGenerator" Version="0.0.9-preview" OutputItemType="Analyzer"  />
  </ItemGroup>
<PropertyGroup>
    
    <InterceptorsPreviewNamespaces>$(InterceptorsPreviewNamespaces);AspectGenerator</InterceptorsPreviewNamespaces>

    <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
    <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
</PropertyGroup>
</Project>


The code that you will use is


using AG;

var p=new Person { FirstName="Ignat", LastName="Andrei" };
var x= p.FullName();
Console.WriteLine(x);   


namespace AG;

internal class Person
{
    public string? FirstName { get; set; }
    public string? LastName { get; set; }
    [Metrics]
    public string FullName()
    {
        return $"{FirstName} {LastName}";
    }
}


using System.Diagnostics;
using AspectGenerator;
namespace AG;

[Aspect(
       // Specify the name of the method used in the 'using' statement
       // that returns an IDisposable object.
       OnUsing = nameof(OnUsing)
       )]
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
sealed class MetricsAttribute : Attribute
{
    //static readonly ActivitySource _activitySource = new("Sample.Aspect");

    public static Activity? OnUsing(InterceptInfo info)
    {
        Console.WriteLine($"Entering {info.MemberInfo.Name}");
        return null;
        //var data=_activitySource.StartActivity(info.MemberInfo.Name);
        //return data;
    }
}

 

The code that is generated is

// <auto-generated/>
#pragma warning disable
#nullable enable

using System;

#if AG_GENERATE_API || !AG_NOT_GENERATE_API

namespace AspectGenerator
{
	/// <summary>
	/// <para>Defines an aspect.</para>
	/// <para>Create a new attribute decorated with this attribute to define an aspect.</para>
	/// </summary>
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
#if AG_PUBLIC_API
	public
#endif
	sealed class AspectAttribute : Attribute
	{
		public string?   OnInit            { get; set; }
		public string?   OnUsing           { get; set; }
		public string?   OnUsingAsync      { get; set; }
		public string?   OnBeforeCall      { get; set; }
		public string?   OnBeforeCallAsync { get; set; }
		public string?   OnCall            { get; set; }
		public string?   OnAfterCall       { get; set; }
		public string?   OnAfterCallAsync  { get; set; }
		public string?   OnCatch           { get; set; }
		public string?   OnCatchAsync      { get; set; }
		public string?   OnFinally         { get; set; }
		public string?   OnFinallyAsync    { get; set; }
		public string[]? InterceptMethods  { get; set; }
		public bool      UseInterceptType  { get; set; }
		public bool      PassArguments     { get; set; }
		public bool      UseInterceptData  { get; set; }
	}

#if AG_PUBLIC_API
	public
#endif
	enum InterceptType
	{
		OnInit,
		OnUsing,
		OnBeforeCall,
		OnAfterCall,
		OnCatch,
		OnFinally
	}

#if AG_PUBLIC_API
	public
#endif
	enum InterceptResult
	{
		Continue,
		Return,
		ReThrow     = Continue,
		IgnoreThrow = Return
	}

#if AG_PUBLIC_API
	public
#endif
	struct Void
	{
	}

#if AG_PUBLIC_API
	public
#endif
	partial class InterceptInfo
	{
		public object?         Tag;
		public InterceptType   InterceptType;
		public InterceptResult InterceptResult;
		public Exception?      Exception;

		public InterceptInfo?                                        PreviousInfo;
		public System.Reflection.MemberInfo                          MemberInfo;
		public object?[]?                                            MethodArguments;
		public Type                                                  AspectType;
		public System.Collections.Generic.Dictionary<string,object?> AspectArguments;
	}

#if AG_PUBLIC_API
	public
#endif
	partial class InterceptInfo<T> : InterceptInfo
	{
		public T ReturnValue;
	}

#if AG_PUBLIC_API
	public
#endif
	partial struct InterceptData<T>
	{
		public object?         Tag;
		public InterceptType   InterceptType;
		public InterceptResult InterceptResult;
		public Exception?      Exception;

		public InterceptInfo<T>?                                     PreviousInfo;
		public System.Reflection.MemberInfo                          MemberInfo;
		public object?[]?                                            MethodArguments;
		public Type                                                  AspectType;
		public System.Collections.Generic.Dictionary<string,object?> AspectArguments;

		public T ReturnValue;
	}
}

#endif

#if AG_GENERATE_InterceptsLocationAttribute || !AG_NOT_GENERATE_InterceptsLocationAttribute

namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
	sealed class InterceptsLocationAttribute(string filePath, int line, int character) : Attribute
	{
	}
}

#endif

// <auto-generated/>
#pragma warning disable
#nullable enable

using System;

using SR  = System.Reflection;
using SLE = System.Linq.Expressions;
using SCG = System.Collections.Generic;

namespace AspectGenerator
{
	using AspectGenerator = AspectGenerator;

	static partial class Interceptors
	{
		static SR.MethodInfo GetMethodInfo(SLE.Expression expr)
		{
			return expr switch
			{
				SLE.MethodCallExpression mc => mc.Method,
				_                           => throw new InvalidOperationException()
			};
		}

		static SR.MethodInfo MethodOf<T>(SLE.Expression<Func<T>> func) => GetMethodInfo(func.Body);
		static SR.MethodInfo MethodOf   (SLE.Expression<Action>  func) => GetMethodInfo(func.Body);

		static SR. MemberInfo                 FullName_Interceptor_MemberInfo        = MethodOf(() => default(AG.Person).FullName());
		static SCG.Dictionary<string,object?> FullName_Interceptor_AspectArguments_0 = new()
		{
		};
		//
		/// <summary>
		/// Intercepts AG.Person.FullName().
		/// </summary>
		//
		// Intercepts p.FullName().
		[System.Runtime.CompilerServices.InterceptsLocation(@"D:\gth\RSCG_Examples\v2\rscg_examples\AspectGenerator\src\AG\Program.cs", line: 4, character: 10)]
		//
		[System.Runtime.CompilerServices.CompilerGenerated]
		//[System.Diagnostics.DebuggerStepThrough]
		public static string FullName_Interceptor(this AG.Person __this__)
		{
			// AG.MetricsAttribute
			//
			var __info__0 = new AspectGenerator.InterceptInfo<string>
			{
				MemberInfo      = FullName_Interceptor_MemberInfo,
				AspectType      = typeof(AG.MetricsAttribute),
				AspectArguments = FullName_Interceptor_AspectArguments_0,
			};

			using (AG.MetricsAttribute.OnUsing(__info__0))
			{
				__info__0.ReturnValue = __this__.FullName();
			}

			return __info__0.ReturnValue;
		}
	}
}

Code and pdf at

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

RSCG – mocklis

RSCG – mocklis
 
 

name mocklis
nuget https://www.nuget.org/packages/mocklis/
link https://mocklis.readthedocs.io/en/latest/getting-started/index.html
author Esbjörn Redmo

Generating mocks from classes for unit tests

 

This is how you can use mocklis .

The code that you start with is


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

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>

    <IsPackable>false</IsPackable>
    <IsTestProject>true</IsTestProject>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0-preview-23577-04" />
    <PackageReference Include="Mocklis" Version="1.4.0-alpha.2" />
    <PackageReference Include="MSTest.TestAdapter" Version="3.2.0-preview.23623.1" />
    <PackageReference Include="MSTest.TestFramework" Version="3.2.0-preview.23623.1" />
    <PackageReference Include="coverlet.collector" Version="6.0.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\MockLisClock\MockLisClock.csproj" />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>

</Project>


The code that you will use is


namespace TestClock;

[MocklisClass]
public partial class TestMock : IMyClock
{

}



using Mocklis;

namespace TestClock;

[TestClass]
public class TestClock
{
    [TestMethod]
    public void TestMyClock()
    {
        var mockSetup = new TestMock();
        mockSetup.GetNow.Return(DateTime.Now.AddYears(-1));

        // When testing the mock like this you need to cast to the interface.
        // This is different from e.g. Moq where the mocked instance and the 'programming interface' are different things.
        // With Mocklis they are the same. The 99% case is where the mock is passed to another constructor as a dependency,
        // in which case there's an implicit cast to the interface.
        var mock = (IMyClock)mockSetup;
        var data = mock.GetNow();
        Assert.AreEqual(DateTime.Now.Year - 1, data.Year);

    }
}


global using Microsoft.VisualStudio.TestTools.UnitTesting;
global using MockTest;
global using Mocklis.Core;

 

The code that is generated is

// <auto-generated />

#nullable enable

namespace TestClock
{
    partial class TestMock
    {
        public global::Mocklis.Core.FuncMethodMock<global::System.DateTime> GetNow { get; }

        global::System.DateTime global::MockTest.IMyClock.GetNow() => GetNow.Call();

        public global::Mocklis.Core.FuncMethodMock<global::System.DateTime> GetUtcNow { get; }

        global::System.DateTime global::MockTest.IMyClock.GetUtcNow() => GetUtcNow.Call();

        public TestMock() : base()
        {
            this.GetNow = new global::Mocklis.Core.FuncMethodMock<global::System.DateTime>(this, "TestMock", "IMyClock", "GetNow", "GetNow", global::Mocklis.Core.Strictness.Lenient);
            this.GetUtcNow = new global::Mocklis.Core.FuncMethodMock<global::System.DateTime>(this, "TestMock", "IMyClock", "GetUtcNow", "GetUtcNow", global::Mocklis.Core.Strictness.Lenient);
        }
    }
}

Code and pdf at

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

RSCG – RSCG_UtilityTypes

RSCG – RSCG_UtilityTypes
 
 

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

Add omit and pick to selectively generate types from existing types

 

This is how you can use RSCG_UtilityTypes .

The code that you start with is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
	  <PackageReference Include="RSCG_UtilityTypes" Version="2023.1223.1230" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
	  <PackageReference Include="RSCG_UtilityTypesCommon" Version="2023.1223.1230" />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using UtilDemo;

var p=new PersonFull();
p.FirstName="Andrei";
p.LastName="Ignat";
Person1 p1=(Person1)p ;
Person2 p2=(Person2)p ;
Console.WriteLine(p1.FirstName);
Console.WriteLine(p2.LastName);


using RSCG_UtilityTypesCommon;

namespace UtilDemo;
[Pick("Person1",nameof(FirstName),nameof(LastName))]
[Omit("Person2", nameof(Salary))]
public class PersonFull
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Salary { get; set; }

}


 

The code that is generated is

namespace UtilDemo
{
partial class Person1
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

public static explicit operator Person1(PersonFull data )
    {
        var ret= new Person1 ();
        ret.FirstName = data.FirstName;
ret.LastName = data.LastName;
        return ret;
    }



public static explicit operator PersonFull(Person1 data )
    {
        var ret= new PersonFull ();
        ret.FirstName = data.FirstName;
ret.LastName = data.LastName;
        return ret;
    }


}
}

namespace UtilDemo
{
partial class Person2
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }

public static explicit operator Person2(PersonFull data )
    {
        var ret= new Person2 ();
        ret.FirstName = data.FirstName;
ret.LastName = data.LastName;
        return ret;
    }



public static explicit operator PersonFull(Person2 data )
    {
        var ret= new PersonFull ();
        ret.FirstName = data.FirstName;
ret.LastName = data.LastName;
        return ret;
    }


}
}

Code and pdf at

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

RSCG – Ling.Audit

RSCG – Ling.Audit
 
 

name Ling.Audit
nuget https://www.nuget.org/packages/Ling.Audit/
link https://github.com/ling921/dotnet-lib/
author Jing Ling

Generating audit data from class implementation of interfaces

 

This is how you can use Ling.Audit .

The code that you start with is


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

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

  <ItemGroup>
    <PackageReference Include="Ling.Audit" Version="1.1.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 LingDemo;

Console.WriteLine("Hello, World!");
var p = new Person();
await Task.Delay(2000);
p.FirstName = "Andrei";
p.LastName = "Ignat";
Console.WriteLine(p.CreationTime);
Console.WriteLine(p.LastModificationTime);


using Ling.Audit;

namespace LingDemo;
partial class Person :IFullAudited<Guid>
{
    public int ID { get; set; }
    public string FirstName { get; set; }= string.Empty;
    public string LastName { get; set; } = string.Empty;
}


 

The code that is generated is

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

namespace LingDemo
{
    partial class Person
    {
        /// <summary>
        /// Gets or sets the creation time of this entity.
        /// </summary>
        public virtual global::System.DateTimeOffset CreationTime { get; set; }
    
        /// <summary>
        /// Gets or sets the creator Id of this entity.
        /// </summary>
        public virtual global::System.Nullable<global::System.Guid> CreatorId { get; set; }
    
        /// <summary>
        /// Gets or sets the last modification time of this entity.
        /// </summary>
        public virtual global::System.Nullable<global::System.DateTimeOffset> LastModificationTime { get; set; }
    
        /// <summary>
        /// Gets or sets the last modifier Id of this entity.
        /// </summary>
        public virtual global::System.Nullable<global::System.Guid> LastModifierId { get; set; }
    
        /// <summary>
        /// Gets or sets whether this entity is soft deleted.
        /// </summary>
        public virtual global::System.Boolean IsDeleted { get; set; }
    
        /// <summary>
        /// Gets or sets the deletion time of this entity.
        /// </summary>
        public virtual global::System.Nullable<global::System.DateTimeOffset> DeletionTime { get; set; }
    
        /// <summary>
        /// Get or set the deleter Id of this entity.
        /// </summary>
        public virtual global::System.Nullable<global::System.Guid> DeleterId { get; set; }
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/Ling.Audit

Blazor and RowNumber in Grid

The data that comes from the backend does not, usually, provide a row number . So how to obtain this ? Create a class, will say any programmer …

public  record DataWithNumber<T>(int number, T data) 
    where T: class
{
}

And the usage

 var data = HttpClient_WebApi.GetFromJsonAsAsyncEnumerable<Order_Details_Extended>(url);
 ArgumentNullException.ThrowIfNull(data);
 int i = 0;

 await foreach (var item in data)
 {
     if (item == null) continue;
     i++;
     dataArr.Add(new DataWithNumber<Order_Details_Extended>(i, item));
     if ((i < 500 && i % 100 == 0) || (i > 500 && i % 1000 == 0))
     {
         Console.WriteLine($"i={i}");
         nrRecordsLoaded = i;

         await InvokeAsync(StateHasChanged);
         await Task.Delay(1000);
     }
 }
 nrRecordsLoaded = i;

And the grid:

<FluentDataGrid Items="@dataForQuery" Virtualize="true" GenerateHeader="GenerateHeaderOption.Sticky">
    <PropertyColumn Property="@(p => p.number)" Sortable="true" />
    <PropertyColumn Property="@(p => p.data.OrderID)" Sortable="true">
        <ColumnOptions>
            <div class="search-box">
                <FluentSearch type="search" Autofocus=true @bind-Value=nameOrderIdFilter @oninput="HandleOrderIdFilter" @bind-Value:after="HandleClearIdFilter" Placeholder="Order Id..." />
            </div>
        </ColumnOptions>
    </PropertyColumn>
    
    <PropertyColumn Property="@(p => p.data.UnitPrice)" Sortable="true" />
    <PropertyColumn Property="@(p => p.data.ExtendedPrice)" Sortable="true" />
    <PropertyColumn Property="@(p => p.data.ProductID)" Sortable="true" />
    <PropertyColumn Property="@(p => p.data.Quantity)" Sortable="true" />
    <PropertyColumn Property="@(p => p.data.Discount)" Sortable="true" />
</FluentDataGrid>

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.