Category: .NET Core

RSCG – SkinnyControllersCommon

RSCG – SkinnyControllersCommon
 
 

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

Automatically add controllers actions for any class injected in constructor

 

This is how you can use SkinnyControllersCommon .

The code that you start with is


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

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

  <ItemGroup>
    <PackageReference Include="SkinnyControllersCommon" Version="2023.5.14.2055" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
  </ItemGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
</Project>


The code that you will use is


using SkinnyControllersDemo.Controllers;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddTransient<WeatherActions>();
var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();



using Microsoft.AspNetCore.Mvc;
using SkinnyControllersCommon;

namespace SkinnyControllersDemo.Controllers;
[AutoActions(template = TemplateIndicator.NoArgs_Is_Get_Else_Post, FieldsName = new[] { "*" }, ExcludeFields = new[] { "_logger" })]
[ApiController]
[Route("[controller]/[action]")]
public partial class WeatherForecastController : ControllerBase
{

    private readonly ILogger<WeatherForecastController> _logger;
    private readonly WeatherActions weather;

    public WeatherForecastController(ILogger<WeatherForecastController> logger, WeatherActions weather)
    {
        _logger = logger;
        this.weather = weather;
    }

    

}


namespace SkinnyControllersDemo.Controllers
{
    public class WeatherActions
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
        public async Task<int> MultiplyBy2(int nr)
        {
            await Task.Delay(nr);
            return nr*2;
        }
    }
}

 

The code that is generated is

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     SkinnyControllersGenerator: 
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using System.Runtime.CompilerServices;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace SkinnyControllersDemo.Controllers {
  [GeneratedCode("SkinnyControllersGenerator", "")]
  [CompilerGenerated]
  partial class WeatherForecastController{ 
    /*[HttpGet()]
    public int id(){
    System.Diagnostics.Debugger.Break();
    return 1;
    } */

      

        [HttpGet] 
        public System.Collections.Generic.IEnumerable<SkinnyControllersDemo.WeatherForecast> Get (){
            //System.Diagnostics.Debugger.Break();
            
                            return 
                        
            weather.Get();

        }
      

        [HttpPost] 
        public System.Threading.Tasks.Task<int> MultiplyBy2 (int nr){
            //System.Diagnostics.Debugger.Break();
            
                            return 
                        
            weather.MultiplyBy2(nr);

        }
      
    
  }
}              

Code and pdf at

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

RSCG – System.Text.RegularExpressions

RSCG – System.Text.RegularExpressions
 
 

name System.Text.RegularExpressions
nuget https://www.nuget.org/packages/System.Text.RegularExpressions/
link https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-source-generators/
author Microsoft

Regex compiled

 

This is how you can use System.Text.RegularExpressions .

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>

</Project>


The code that you will use is


using Demo;
//https://learn.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-source-generators
//https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/
var x = "Abc";
Console.WriteLine(DemoRegex.EvaluateText(x));


using System.Text.RegularExpressions;

namespace Demo;

public partial class DemoRegex
{
    [GeneratedRegex("abc|def", RegexOptions.IgnoreCase, "en-US")]
    private static partial Regex AbcOrDefGeneratedRegex();

    public static bool EvaluateText(string text)
    {
        return (AbcOrDefGeneratedRegex().IsMatch(text));
        
    }
}


 

The code that is generated is

// <auto-generated/>
#nullable enable
#pragma warning disable CS0162 // Unreachable code
#pragma warning disable CS0164 // Unreferenced label
#pragma warning disable CS0219 // Variable assigned but never used

namespace Demo
{
    partial class DemoRegex
    {
        /// <remarks>
        /// Pattern explanation:<br/>
        /// <code>
        /// ○ Match with 2 alternative expressions, atomically.<br/>
        ///     ○ Match a sequence of expressions.<br/>
        ///         ○ Match a character in the set [Aa].<br/>
        ///         ○ Match a character in the set [Bb].<br/>
        ///         ○ Match a character in the set [Cc].<br/>
        ///     ○ Match a sequence of expressions.<br/>
        ///         ○ Match a character in the set [Dd].<br/>
        ///         ○ Match a character in the set [Ee].<br/>
        ///         ○ Match a character in the set [Ff].<br/>
        /// </code>
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "7.0.8.17405")]
        private static partial global::System.Text.RegularExpressions.Regex AbcOrDefGeneratedRegex() => global::System.Text.RegularExpressions.Generated.AbcOrDefGeneratedRegex_0.Instance;
    }
}

namespace System.Text.RegularExpressions.Generated
{
    using System;
    using System.CodeDom.Compiler;
    using System.Collections;
    using System.ComponentModel;
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Text.RegularExpressions;
    using System.Threading;

    /// <summary>Custom <see cref="Regex"/>-derived type for the AbcOrDefGeneratedRegex method.</summary>
    [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "7.0.8.17405")]
    file sealed class AbcOrDefGeneratedRegex_0 : Regex
    {
        /// <summary>Cached, thread-safe singleton instance.</summary>
        internal static readonly AbcOrDefGeneratedRegex_0 Instance = new();
    
        /// <summary>Initializes the instance.</summary>
        private AbcOrDefGeneratedRegex_0()
        {
            base.pattern = "abc|def";
            base.roptions = RegexOptions.IgnoreCase;
            ValidateMatchTimeout(Utilities.s_defaultTimeout);
            base.internalMatchTimeout = Utilities.s_defaultTimeout;
            base.factory = new RunnerFactory();
            base.capsize = 1;
        }
    
        /// <summary>Provides a factory for creating <see cref="RegexRunner"/> instances to be used by methods on <see cref="Regex"/>.</summary>
        private sealed class RunnerFactory : RegexRunnerFactory
        {
            /// <summary>Creates an instance of a <see cref="RegexRunner"/> used by methods on <see cref="Regex"/>.</summary>
            protected override RegexRunner CreateInstance() => new Runner();
        
            /// <summary>Provides the runner that contains the custom logic implementing the specified regular expression.</summary>
            private sealed class Runner : RegexRunner
            {
                /// <summary>Scan the <paramref name="inputSpan"/> starting from base.runtextstart for the next match.</summary>
                /// <param name="inputSpan">The text being scanned by the regular expression.</param>
                protected override void Scan(ReadOnlySpan<char> inputSpan)
                {
                    // Search until we can't find a valid starting position, we find a match, or we reach the end of the input.
                    while (TryFindNextPossibleStartingPosition(inputSpan) &&
                           !TryMatchAtCurrentPosition(inputSpan) &&
                           base.runtextpos != inputSpan.Length)
                    {
                        base.runtextpos++;
                        if (Utilities.s_hasTimeout)
                        {
                            base.CheckTimeout();
                        }
                    }
                }
        
                /// <summary>Search <paramref name="inputSpan"/> starting from base.runtextpos for the next location a match could possibly start.</summary>
                /// <param name="inputSpan">The text being scanned by the regular expression.</param>
                /// <returns>true if a possible match was found; false if no more matches are possible.</returns>
                private bool TryFindNextPossibleStartingPosition(ReadOnlySpan<char> inputSpan)
                {
                    int pos = base.runtextpos;
                    ulong charMinusLow;
                    
                    // Any possible match is at least 3 characters.
                    if (pos <= inputSpan.Length - 3)
                    {
                        // The pattern matches a character in the set [CFcf] at index 2.
                        // Find the next occurrence. If it can't be found, there's no match.
                        ReadOnlySpan<char> span = inputSpan.Slice(pos);
                        for (int i = 0; i < span.Length - 2; i++)
                        {
                            int indexOfPos = span.Slice(i + 2).IndexOfAny("CFcf");
                            if (indexOfPos < 0)
                            {
                                goto NoMatchFound;
                            }
                            i += indexOfPos;
                            
                            if (((long)((0x9000000090000000UL << (int)(charMinusLow = (uint)span[i] - 'A')) & (charMinusLow - 64)) < 0) &&
                                ((long)((0x9000000090000000UL << (int)(charMinusLow = (uint)span[i + 1] - 'B')) & (charMinusLow - 64)) < 0))
                            {
                                base.runtextpos = pos + i;
                                return true;
                            }
                        }
                    }
                    
                    // No match found.
                    NoMatchFound:
                    base.runtextpos = inputSpan.Length;
                    return false;
                }
        
                /// <summary>Determine whether <paramref name="inputSpan"/> at base.runtextpos is a match for the regular expression.</summary>
                /// <param name="inputSpan">The text being scanned by the regular expression.</param>
                /// <returns>true if the regular expression matches at the current position; otherwise, false.</returns>
                private bool TryMatchAtCurrentPosition(ReadOnlySpan<char> inputSpan)
                {
                    int pos = base.runtextpos;
                    int matchStart = pos;
                    ReadOnlySpan<char> slice = inputSpan.Slice(pos);
                    
                    // Match with 2 alternative expressions, atomically.
                    {
                        if (slice.IsEmpty)
                        {
                            return false; // The input didn't match.
                        }
                        
                        switch (slice[0])
                        {
                            case 'A' or 'a':
                                if ((uint)slice.Length < 3 ||
                                    !slice.Slice(1).StartsWith("bc", StringComparison.OrdinalIgnoreCase)) // Match the string "bc" (ordinal case-insensitive)
                                {
                                    return false; // The input didn't match.
                                }
                                
                                pos += 3;
                                slice = inputSpan.Slice(pos);
                                break;
                                
                            case 'D' or 'd':
                                if ((uint)slice.Length < 3 ||
                                    !slice.Slice(1).StartsWith("ef", StringComparison.OrdinalIgnoreCase)) // Match the string "ef" (ordinal case-insensitive)
                                {
                                    return false; // The input didn't match.
                                }
                                
                                pos += 3;
                                slice = inputSpan.Slice(pos);
                                break;
                                
                            default:
                                return false; // The input didn't match.
                        }
                    }
                    
                    // The input matched.
                    base.runtextpos = pos;
                    base.Capture(0, matchStart, pos);
                    return true;
                }
            }
        }

    }
    
    /// <summary>Helper methods used by generated <see cref="Regex"/>-derived implementations.</summary>
    [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "7.0.8.17405")]
    file static class Utilities
    {
        /// <summary>Default timeout value set in <see cref="AppContext"/>, or <see cref="Regex.InfiniteMatchTimeout"/> if none was set.</summary>
        internal static readonly TimeSpan s_defaultTimeout = AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeout ? timeout : Regex.InfiniteMatchTimeout;
        
        /// <summary>Whether <see cref="s_defaultTimeout"/> is non-infinite.</summary>
        internal static readonly bool s_hasTimeout = s_defaultTimeout != Timeout.InfiniteTimeSpan;
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/System.Text.RegularExpressions

RSCG – RSCG_Utils

RSCG – RSCG_Utils
 
 

name RSCG_Utils
nuget https://www.nuget.org/packages/RSCG_Utils
link https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation
author Ignat Andrei

Add files as C# consts

 

This is how you can use RSCG_Utils .

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="rscgutils" Version="2023.514.835" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
  
  </ItemGroup>
	<ItemGroup>
		<AdditionalFiles Include="data.gen.txt" />
	</ItemGroup>

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


</Project>


The code that you will use is


Console.WriteLine("Hello, World!");
string dataFromFile = MyAdditionalFiles.data_gen_txt;
Console.Write(dataFromFile);


This is a data
That you will retrieve
as C# const

 

The code that is generated is


    public static partial class MyAdditionalFiles
    {
        //https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string                
        public const string data_gen_txt =  """"""""""
This is a data
That you will retrieve
as C# const
"""""""""";
    }

Code and pdf at

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

RSCG – System.Text.Json

 
 

name System.Text.Json
nuget https://www.nuget.org/packages/System.Text.Json/
link https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation
author Microsoft

Json Serialize without reflection

 

This is how you can use System.Text.Json .

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>

</Project>


The code that you will use is


using JsonSerializerOptionsExample;
using System.Text.Json;
//for asp.net core
//services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.AddContext<MyJsonContext>());
//https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string

string jsonString ="""
{
  "date": "2019-08-01T00:00:00",
  "temperatureCelsius": 25,
  "summary": "Hot"
}
""";
        WeatherForecast? weatherForecast= JsonSerializer.Deserialize(
            jsonString,
            typeof(WeatherForecast),
            new OptionsExampleContext(
                new JsonSerializerOptions(JsonSerializerDefaults.Web)))
                as WeatherForecast;
        Console.WriteLine($"Date={weatherForecast?.Date}");
        // output:
        //Date=8/1/2019 12:00:00 AM

        jsonString = JsonSerializer.Serialize(
            weatherForecast,
            typeof(WeatherForecast),
            new OptionsExampleContext(
                new JsonSerializerOptions(JsonSerializerDefaults.Web)));
        Console.WriteLine(jsonString);
jsonString = JsonSerializer.Serialize(
    weatherForecast,
    typeof(WeatherForecast),
    new OptionsExampleContext(
        new JsonSerializerOptions(JsonSerializerDefaults.General)));
Console.WriteLine(jsonString);
// output:
//{ "date":"2019-08-01T00:00:00","temperatureCelsius":25,"summary":"Hot"}



namespace JsonSerializerOptionsExample;

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}



using System.Text.Json.Serialization;

namespace JsonSerializerOptionsExample;

[JsonSerializable(typeof(WeatherForecast))]
internal partial class OptionsExampleContext : JsonSerializerContext
{
}


 

The code that is generated is

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

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

namespace JsonSerializerOptionsExample
{
    internal partial class OptionsExampleContext
    {
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.DateTime>? _DateTime;
        /// <summary>
        /// Defines the source generated JSON serialization contract metadata for a given type.
        /// </summary>
        public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.DateTime> DateTime
        {
            get => _DateTime ??= Create_DateTime(Options, makeReadOnly: true);
        }
        
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.DateTime> Create_DateTime(global::System.Text.Json.JsonSerializerOptions options, bool makeReadOnly)
        {
            global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.DateTime>? jsonTypeInfo = null;
            global::System.Text.Json.Serialization.JsonConverter? customConverter;
            if (options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::System.DateTime))) != null)
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::System.DateTime>(options, customConverter);
            }
            else
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::System.DateTime>(options, global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.DateTimeConverter);
            }
        
            if (makeReadOnly)
            {
                jsonTypeInfo.MakeReadOnly();
            }
        
            return jsonTypeInfo;
        }
        
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

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

namespace JsonSerializerOptionsExample
{
    
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.Json.SourceGeneration", "7.0.8.17405")]
    internal partial class OptionsExampleContext
    {
        
        private static global::System.Text.Json.JsonSerializerOptions s_defaultOptions { get; } = new global::System.Text.Json.JsonSerializerOptions()
        {
            DefaultIgnoreCondition = global::System.Text.Json.Serialization.JsonIgnoreCondition.Never,
            IgnoreReadOnlyFields = false,
            IgnoreReadOnlyProperties = false,
            IncludeFields = false,
            WriteIndented = false,
        };
        
        private static global::JsonSerializerOptionsExample.OptionsExampleContext? s_defaultContext;
        
        /// <summary>
        /// The default <see cref="global::System.Text.Json.Serialization.JsonSerializerContext"/> associated with a default <see cref="global::System.Text.Json.JsonSerializerOptions"/> instance.
        /// </summary>
        public static global::JsonSerializerOptionsExample.OptionsExampleContext Default => s_defaultContext ??= new global::JsonSerializerOptionsExample.OptionsExampleContext(new global::System.Text.Json.JsonSerializerOptions(s_defaultOptions));
        
        /// <summary>
        /// The source-generated options associated with this context.
        /// </summary>
        protected override global::System.Text.Json.JsonSerializerOptions? GeneratedSerializerOptions { get; } = s_defaultOptions;
        
        /// <inheritdoc/>
        public OptionsExampleContext() : base(null)
        {
        }
        
        /// <inheritdoc/>
        public OptionsExampleContext(global::System.Text.Json.JsonSerializerOptions options) : base(options)
        {
        }
        
        private static global::System.Text.Json.Serialization.JsonConverter? GetRuntimeProvidedCustomConverter(global::System.Text.Json.JsonSerializerOptions options, global::System.Type type)
        {
            global::System.Collections.Generic.IList<global::System.Text.Json.Serialization.JsonConverter> converters = options.Converters;
        
            for (int i = 0; i < converters.Count; i++)
            {
                global::System.Text.Json.Serialization.JsonConverter? converter = converters[i];
        
                if (converter.CanConvert(type))
                {
                    if (converter is global::System.Text.Json.Serialization.JsonConverterFactory factory)
                    {
                        converter = factory.CreateConverter(type, options);
                        if (converter == null || converter is global::System.Text.Json.Serialization.JsonConverterFactory)
                        {
                            throw new global::System.InvalidOperationException(string.Format("The converter '{0}' cannot return null or a JsonConverterFactory instance.", factory.GetType()));
                        }
                    }
        
                    return converter;
                }
            }
        
            return null;
        }
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

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

namespace JsonSerializerOptionsExample
{
    internal partial class OptionsExampleContext: global::System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver
    {
        /// <inheritdoc/>
        public override global::System.Text.Json.Serialization.Metadata.JsonTypeInfo GetTypeInfo(global::System.Type type)
        {
            if (type == typeof(global::JsonSerializerOptionsExample.WeatherForecast))
            {
                return this.WeatherForecast;
            }
        
            if (type == typeof(global::System.DateTime))
            {
                return this.DateTime;
            }
        
            if (type == typeof(global::System.Int32))
            {
                return this.Int32;
            }
        
            if (type == typeof(global::System.String))
            {
                return this.String;
            }
        
            return null!;
        }
        
        global::System.Text.Json.Serialization.Metadata.JsonTypeInfo? global::System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver.GetTypeInfo(global::System.Type type, global::System.Text.Json.JsonSerializerOptions options)
        {
            if (type == typeof(global::JsonSerializerOptionsExample.WeatherForecast))
            {
                return Create_WeatherForecast(options, makeReadOnly: false);
            }
        
            if (type == typeof(global::System.DateTime))
            {
                return Create_DateTime(options, makeReadOnly: false);
            }
        
            if (type == typeof(global::System.Int32))
            {
                return Create_Int32(options, makeReadOnly: false);
            }
        
            if (type == typeof(global::System.String))
            {
                return Create_String(options, makeReadOnly: false);
            }
        
            return null;
        }
        
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

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

namespace JsonSerializerOptionsExample
{
    internal partial class OptionsExampleContext
    {
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.Int32>? _Int32;
        /// <summary>
        /// Defines the source generated JSON serialization contract metadata for a given type.
        /// </summary>
        public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.Int32> Int32
        {
            get => _Int32 ??= Create_Int32(Options, makeReadOnly: true);
        }
        
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.Int32> Create_Int32(global::System.Text.Json.JsonSerializerOptions options, bool makeReadOnly)
        {
            global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.Int32>? jsonTypeInfo = null;
            global::System.Text.Json.Serialization.JsonConverter? customConverter;
            if (options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::System.Int32))) != null)
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::System.Int32>(options, customConverter);
            }
            else
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::System.Int32>(options, global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.Int32Converter);
            }
        
            if (makeReadOnly)
            {
                jsonTypeInfo.MakeReadOnly();
            }
        
            return jsonTypeInfo;
        }
        
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

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

namespace JsonSerializerOptionsExample
{
    internal partial class OptionsExampleContext
    {
        
        private static readonly global::System.Text.Json.JsonEncodedText PropName_Date = global::System.Text.Json.JsonEncodedText.Encode("Date");
        private static readonly global::System.Text.Json.JsonEncodedText PropName_TemperatureCelsius = global::System.Text.Json.JsonEncodedText.Encode("TemperatureCelsius");
        private static readonly global::System.Text.Json.JsonEncodedText PropName_Summary = global::System.Text.Json.JsonEncodedText.Encode("Summary");
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

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

namespace JsonSerializerOptionsExample
{
    internal partial class OptionsExampleContext
    {
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.String>? _String;
        /// <summary>
        /// Defines the source generated JSON serialization contract metadata for a given type.
        /// </summary>
        public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.String> String
        {
            get => _String ??= Create_String(Options, makeReadOnly: true);
        }
        
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.String> Create_String(global::System.Text.Json.JsonSerializerOptions options, bool makeReadOnly)
        {
            global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::System.String>? jsonTypeInfo = null;
            global::System.Text.Json.Serialization.JsonConverter? customConverter;
            if (options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::System.String))) != null)
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::System.String>(options, customConverter);
            }
            else
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::System.String>(options, global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.StringConverter);
            }
        
            if (makeReadOnly)
            {
                jsonTypeInfo.MakeReadOnly();
            }
        
            return jsonTypeInfo;
        }
        
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

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

namespace JsonSerializerOptionsExample
{
    internal partial class OptionsExampleContext
    {
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::JsonSerializerOptionsExample.WeatherForecast>? _WeatherForecast;
        /// <summary>
        /// Defines the source generated JSON serialization contract metadata for a given type.
        /// </summary>
        public global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::JsonSerializerOptionsExample.WeatherForecast> WeatherForecast
        {
            get => _WeatherForecast ??= Create_WeatherForecast(Options, makeReadOnly: true);
        }
        
        private global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::JsonSerializerOptionsExample.WeatherForecast> Create_WeatherForecast(global::System.Text.Json.JsonSerializerOptions options, bool makeReadOnly)
        {
            global::System.Text.Json.Serialization.Metadata.JsonTypeInfo<global::JsonSerializerOptionsExample.WeatherForecast>? jsonTypeInfo = null;
            global::System.Text.Json.Serialization.JsonConverter? customConverter;
            if (options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(options, typeof(global::JsonSerializerOptionsExample.WeatherForecast))) != null)
            {
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateValueInfo<global::JsonSerializerOptionsExample.WeatherForecast>(options, customConverter);
            }
            else
            {
                global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::JsonSerializerOptionsExample.WeatherForecast> objectInfo = new global::System.Text.Json.Serialization.Metadata.JsonObjectInfoValues<global::JsonSerializerOptionsExample.WeatherForecast>()
                {
                    ObjectCreator = static () => new global::JsonSerializerOptionsExample.WeatherForecast(),
                    ObjectWithParameterizedConstructorCreator = null,
                    PropertyMetadataInitializer = _ => WeatherForecastPropInit(options),
                    ConstructorParameterMetadataInitializer = null,
                    NumberHandling = default,
                    SerializeHandler = WeatherForecastSerializeHandler
                };
        
                jsonTypeInfo = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreateObjectInfo<global::JsonSerializerOptionsExample.WeatherForecast>(options, objectInfo);
            }
        
            if (makeReadOnly)
            {
                jsonTypeInfo.MakeReadOnly();
            }
        
            return jsonTypeInfo;
        }
        
        private static global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] WeatherForecastPropInit(global::System.Text.Json.JsonSerializerOptions options)
        {
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[] properties = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo[3];
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::System.DateTime> info0 = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::System.DateTime>()
            {
                IsProperty = true,
                IsPublic = true,
                IsVirtual = false,
                DeclaringType = typeof(global::JsonSerializerOptionsExample.WeatherForecast),
                Converter = null,
                Getter = static (obj) => ((global::JsonSerializerOptionsExample.WeatherForecast)obj).Date,
                Setter = static (obj, value) => ((global::JsonSerializerOptionsExample.WeatherForecast)obj).Date = value!,
                IgnoreCondition = null,
                HasJsonInclude = false,
                IsExtensionData = false,
                NumberHandling = default,
                PropertyName = "Date",
                JsonPropertyName = null
            };
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo propertyInfo0 = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreatePropertyInfo<global::System.DateTime>(options, info0);
            properties[0] = propertyInfo0;
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::System.Int32> info1 = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::System.Int32>()
            {
                IsProperty = true,
                IsPublic = true,
                IsVirtual = false,
                DeclaringType = typeof(global::JsonSerializerOptionsExample.WeatherForecast),
                Converter = null,
                Getter = static (obj) => ((global::JsonSerializerOptionsExample.WeatherForecast)obj).TemperatureCelsius,
                Setter = static (obj, value) => ((global::JsonSerializerOptionsExample.WeatherForecast)obj).TemperatureCelsius = value!,
                IgnoreCondition = null,
                HasJsonInclude = false,
                IsExtensionData = false,
                NumberHandling = default,
                PropertyName = "TemperatureCelsius",
                JsonPropertyName = null
            };
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo propertyInfo1 = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreatePropertyInfo<global::System.Int32>(options, info1);
            properties[1] = propertyInfo1;
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::System.String> info2 = new global::System.Text.Json.Serialization.Metadata.JsonPropertyInfoValues<global::System.String>()
            {
                IsProperty = true,
                IsPublic = true,
                IsVirtual = false,
                DeclaringType = typeof(global::JsonSerializerOptionsExample.WeatherForecast),
                Converter = null,
                Getter = static (obj) => ((global::JsonSerializerOptionsExample.WeatherForecast)obj).Summary!,
                Setter = static (obj, value) => ((global::JsonSerializerOptionsExample.WeatherForecast)obj).Summary = value!,
                IgnoreCondition = null,
                HasJsonInclude = false,
                IsExtensionData = false,
                NumberHandling = default,
                PropertyName = "Summary",
                JsonPropertyName = null
            };
        
            global::System.Text.Json.Serialization.Metadata.JsonPropertyInfo propertyInfo2 = global::System.Text.Json.Serialization.Metadata.JsonMetadataServices.CreatePropertyInfo<global::System.String>(options, info2);
            properties[2] = propertyInfo2;
        
            return properties;
        }
        
        // Intentionally not a static method because we create a delegate to it. Invoking delegates to instance
        // methods is almost as fast as virtual calls. Static methods need to go through a shuffle thunk.
        private void WeatherForecastSerializeHandler(global::System.Text.Json.Utf8JsonWriter writer, global::JsonSerializerOptionsExample.WeatherForecast? value)
        {
            if (value == null)
            {
                writer.WriteNullValue();
                return;
            }
        
            writer.WriteStartObject();
            writer.WriteString(PropName_Date, value.Date);
            writer.WriteNumber(PropName_TemperatureCelsius, value.TemperatureCelsius);
            writer.WriteString(PropName_Summary, value.Summary);
        
            writer.WriteEndObject();
        }
    }
}

// <auto-generated/>

#nullable enable annotations
#nullable disable warnings

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

namespace BothModesNoOptions
{
    
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.Json.SourceGeneration", "7.0.8.17405")]
    internal partial class SourceGenerationContext
    {
        
        private static global::System.Text.Json.JsonSerializerOptions s_defaultOptions { get; } = new global::System.Text.Json.JsonSerializerOptions()
        {
            DefaultIgnoreCondition = global::System.Text.Json.Serialization.JsonIgnoreCondition.Never,
            IgnoreReadOnlyFields = false,
            IgnoreReadOnlyProperties = false,
            IncludeFields = false,
            WriteIndented = true,
        };
        
        private static global::BothModesNoOptions.SourceGenerationContext? s_defaultContext;
        
        /// <summary>
        /// The default <see cref="global::System.Text.Json.Serialization.JsonSerializerContext"/> associated with a default <see cref="global::System.Text.Json.JsonSerializerOptions"/> instance.
        /// </summary>
        public static global::BothModesNoOptions.SourceGenerationContext Default => s_defaultContext ??= new global::BothModesNoOptions.SourceGenerationContext(new global::System.Text.Json.JsonSerializerOptions(s_defaultOptions));
        
        /// <summary>
        /// The source-generated options associated with this context.
        /// </summary>
        protected override global::System.Text.Json.JsonSerializerOptions? GeneratedSerializerOptions { get; } = s_defaultOptions;
        
        /// <inheritdoc/>
        public SourceGenerationContext() : base(null)
        {
        }
        
        /// <inheritdoc/>
        public SourceGenerationContext(global::System.Text.Json.JsonSerializerOptions options) : base(options)
        {
        }
        
        private static global::System.Text.Json.Serialization.JsonConverter? GetRuntimeProvidedCustomConverter(global::System.Text.Json.JsonSerializerOptions options, global::System.Type type)
        {
            global::System.Collections.Generic.IList<global::System.Text.Json.Serialization.JsonConverter> converters = options.Converters;
        
            for (int i = 0; i < converters.Count; i++)
            {
                global::System.Text.Json.Serialization.JsonConverter? converter = converters[i];
        
                if (converter.CanConvert(type))
                {
                    if (converter is global::System.Text.Json.Serialization.JsonConverterFactory factory)
                    {
                        converter = factory.CreateConverter(type, options);
                        if (converter == null || converter is global::System.Text.Json.Serialization.JsonConverterFactory)
                        {
                            throw new global::System.InvalidOperationException(string.Format("The converter '{0}' cannot return null or a JsonConverterFactory instance.", factory.GetType()));
                        }
                    }
        
                    return converter;
                }
            }
        
            return null;
        }
    }
}

// <auto-generated/>
#nullable enable
#pragma warning disable CS0162 // Unreachable code
#pragma warning disable CS0164 // Unreferenced label
#pragma warning disable CS0219 // Variable assigned but never used

namespace JsonSerializerOptionsExample
{
    partial class WeatherForecast
    {
        /// <remarks>
        /// Pattern explanation:<br/>
        /// <code>
        /// ○ Match with 2 alternative expressions, atomically.<br/>
        ///     ○ Match a sequence of expressions.<br/>
        ///         ○ Match a character in the set [Aa].<br/>
        ///         ○ Match a character in the set [Bb].<br/>
        ///         ○ Match a character in the set [Cc].<br/>
        ///     ○ Match a sequence of expressions.<br/>
        ///         ○ Match a character in the set [Dd].<br/>
        ///         ○ Match a character in the set [Ee].<br/>
        ///         ○ Match a character in the set [Ff].<br/>
        /// </code>
        /// </remarks>
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "7.0.8.17405")]
        private static partial global::System.Text.RegularExpressions.Regex AbcOrDefGeneratedRegex() => global::System.Text.RegularExpressions.Generated.AbcOrDefGeneratedRegex_0.Instance;
    }
}

namespace System.Text.RegularExpressions.Generated
{
    using System;
    using System.CodeDom.Compiler;
    using System.Collections;
    using System.ComponentModel;
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Text.RegularExpressions;
    using System.Threading;

    /// <summary>Custom <see cref="Regex"/>-derived type for the AbcOrDefGeneratedRegex method.</summary>
    [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "7.0.8.17405")]
    file sealed class AbcOrDefGeneratedRegex_0 : Regex
    {
        /// <summary>Cached, thread-safe singleton instance.</summary>
        internal static readonly AbcOrDefGeneratedRegex_0 Instance = new();
    
        /// <summary>Initializes the instance.</summary>
        private AbcOrDefGeneratedRegex_0()
        {
            base.pattern = "abc|def";
            base.roptions = RegexOptions.IgnoreCase;
            ValidateMatchTimeout(Utilities.s_defaultTimeout);
            base.internalMatchTimeout = Utilities.s_defaultTimeout;
            base.factory = new RunnerFactory();
            base.capsize = 1;
        }
    
        /// <summary>Provides a factory for creating <see cref="RegexRunner"/> instances to be used by methods on <see cref="Regex"/>.</summary>
        private sealed class RunnerFactory : RegexRunnerFactory
        {
            /// <summary>Creates an instance of a <see cref="RegexRunner"/> used by methods on <see cref="Regex"/>.</summary>
            protected override RegexRunner CreateInstance() => new Runner();
        
            /// <summary>Provides the runner that contains the custom logic implementing the specified regular expression.</summary>
            private sealed class Runner : RegexRunner
            {
                /// <summary>Scan the <paramref name="inputSpan"/> starting from base.runtextstart for the next match.</summary>
                /// <param name="inputSpan">The text being scanned by the regular expression.</param>
                protected override void Scan(ReadOnlySpan<char> inputSpan)
                {
                    // Search until we can't find a valid starting position, we find a match, or we reach the end of the input.
                    while (TryFindNextPossibleStartingPosition(inputSpan) &&
                           !TryMatchAtCurrentPosition(inputSpan) &&
                           base.runtextpos != inputSpan.Length)
                    {
                        base.runtextpos++;
                        if (Utilities.s_hasTimeout)
                        {
                            base.CheckTimeout();
                        }
                    }
                }
        
                /// <summary>Search <paramref name="inputSpan"/> starting from base.runtextpos for the next location a match could possibly start.</summary>
                /// <param name="inputSpan">The text being scanned by the regular expression.</param>
                /// <returns>true if a possible match was found; false if no more matches are possible.</returns>
                private bool TryFindNextPossibleStartingPosition(ReadOnlySpan<char> inputSpan)
                {
                    int pos = base.runtextpos;
                    ulong charMinusLow;
                    
                    // Any possible match is at least 3 characters.
                    if (pos <= inputSpan.Length - 3)
                    {
                        // The pattern matches a character in the set [CFcf] at index 2.
                        // Find the next occurrence. If it can't be found, there's no match.
                        ReadOnlySpan<char> span = inputSpan.Slice(pos);
                        for (int i = 0; i < span.Length - 2; i++)
                        {
                            int indexOfPos = span.Slice(i + 2).IndexOfAny("CFcf");
                            if (indexOfPos < 0)
                            {
                                goto NoMatchFound;
                            }
                            i += indexOfPos;
                            
                            if (((long)((0x9000000090000000UL << (int)(charMinusLow = (uint)span[i] - 'A')) & (charMinusLow - 64)) < 0) &&
                                ((long)((0x9000000090000000UL << (int)(charMinusLow = (uint)span[i + 1] - 'B')) & (charMinusLow - 64)) < 0))
                            {
                                base.runtextpos = pos + i;
                                return true;
                            }
                        }
                    }
                    
                    // No match found.
                    NoMatchFound:
                    base.runtextpos = inputSpan.Length;
                    return false;
                }
        
                /// <summary>Determine whether <paramref name="inputSpan"/> at base.runtextpos is a match for the regular expression.</summary>
                /// <param name="inputSpan">The text being scanned by the regular expression.</param>
                /// <returns>true if the regular expression matches at the current position; otherwise, false.</returns>
                private bool TryMatchAtCurrentPosition(ReadOnlySpan<char> inputSpan)
                {
                    int pos = base.runtextpos;
                    int matchStart = pos;
                    ReadOnlySpan<char> slice = inputSpan.Slice(pos);
                    
                    // Match with 2 alternative expressions, atomically.
                    {
                        if (slice.IsEmpty)
                        {
                            return false; // The input didn't match.
                        }
                        
                        switch (slice[0])
                        {
                            case 'A' or 'a':
                                if ((uint)slice.Length < 3 ||
                                    !slice.Slice(1).StartsWith("bc", StringComparison.OrdinalIgnoreCase)) // Match the string "bc" (ordinal case-insensitive)
                                {
                                    return false; // The input didn't match.
                                }
                                
                                pos += 3;
                                slice = inputSpan.Slice(pos);
                                break;
                                
                            case 'D' or 'd':
                                if ((uint)slice.Length < 3 ||
                                    !slice.Slice(1).StartsWith("ef", StringComparison.OrdinalIgnoreCase)) // Match the string "ef" (ordinal case-insensitive)
                                {
                                    return false; // The input didn't match.
                                }
                                
                                pos += 3;
                                slice = inputSpan.Slice(pos);
                                break;
                                
                            default:
                                return false; // The input didn't match.
                        }
                    }
                    
                    // The input matched.
                    base.runtextpos = pos;
                    base.Capture(0, matchStart, pos);
                    return true;
                }
            }
        }

    }
    
    /// <summary>Helper methods used by generated <see cref="Regex"/>-derived implementations.</summary>
    [GeneratedCodeAttribute("System.Text.RegularExpressions.Generator", "7.0.8.17405")]
    file static class Utilities
    {
        /// <summary>Default timeout value set in <see cref="AppContext"/>, or <see cref="Regex.InfiniteMatchTimeout"/> if none was set.</summary>
        internal static readonly TimeSpan s_defaultTimeout = AppContext.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") is TimeSpan timeout ? timeout : Regex.InfiniteMatchTimeout;
        
        /// <summary>Whether <see cref="s_defaultTimeout"/> is non-infinite.</summary>
        internal static readonly bool s_hasTimeout = s_defaultTimeout != Timeout.InfiniteTimeSpan;
    }
}

Code and pdf at

https://ignatandrei.github.io/RSCG_Examples/v2/docs/System.Text.Json

RSCG – RSCG_TimeBombComment

 
 

name RSCG_TimeBombComment
nuget https://www.nuget.org/packages/RSCG_TimeBombComment/
link http://msprogrammer.serviciipeweb.ro/category/roslyn/
author Andrei Ignat

This will generate an error from the comment after a certain date

 

This is how you can use RSCG_TimeBombComment .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net7.0</TargetFramework>
	</PropertyGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="RSCG_TimeBombComment" Version="2023.5.9.2110" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
	</ItemGroup>
</Project>


The code that you will use is


namespace Console_TimeBombComment;
internal partial class TestClass
{
    [Obsolete("this will be obsolete",TB_20230508)]
    public int DataObsolete()
    {
        return 5;
    }

    public int CommentsWithErrors()
    {
        //JFD: test
        //TB: 2021-09-13 this is a comment transformed into an error
        //TB: and this is a warning
        //TB: 2050-12-30 and this should not appear yet
        return 5;
    }
}


 

The code that is generated is


namespace Console_TimeBombComment {
    partial class TestClass { 
        const bool TB_20230508 = true;
    }
}

                

Code and pdf at

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

RSCG – ThisAssembly

RSCG – ThisAssembly
 
 

name ThisAssembly
nuget https://www.nuget.org/packages/ThisAssembly
link https://www.clarius.org/ThisAssembly/
author Daniel Cazzulino

The ThisAssembly.Info allows you access to the Assembly Information as constants, instead of going to reflection each time.

I found useful to see the assembly version right away in any project that I have.

 

This is how you can use ThisAssembly .

The code that you start with is


<Project Sdk="Microsoft.NET.Sdk">
	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>netcoreapp7.0</TargetFramework>
	</PropertyGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
	<PropertyGroup>
		<Version>2023.5.7.800</Version>
	</PropertyGroup>
	<ItemGroup>
		<PackageReference Include="ThisAssembly" Version="1.2.14" OutputItemType="Analyzer" ReferenceOutputAssembly="false">
			<PrivateAssets>all</PrivateAssets>
			<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
		</PackageReference>
	</ItemGroup>
</Project>


The code that you will use is


var strVersion = ThisAssembly.Info.Version;
System.Console.WriteLine(strVersion);


 

The code that is generated is

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

using System.CodeDom.Compiler;
using System.Runtime.CompilerServices;

/// <summary>
/// Provides access to the current assembly information as pure constants, 
///  without requiring reflection.
/// </summary>
partial class ThisAssembly
{
    /// <summary>
    /// Gets the AssemblyInfo attributes.
    /// </summary>
    [GeneratedCode("ThisAssembly.AssemblyInfo", "1.2.14")]
    [CompilerGenerated]
    public static partial class Info
    {
        public const string Company = @"RSCG_Version";

        public const string Configuration = @"Debug";

        public const string FileVersion = @"2023.5.7.800";

        public const string InformationalVersion = @"2023.5.7.800";

        public const string Product = @"RSCG_Version";

        public const string Title = @"RSCG_Version";

        public const string Version = @"2023.5.7.800";

    }
}
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     ThisAssembly.Constants: 1.2.14
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Globalization;

partial class ThisAssembly
{
    public static partial class Git
    {
        /// <summary>
        /// => @"[pending build]"
        /// </summary>
        public const string Branch = @"[pending build]";
    }
}
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     ThisAssembly.Constants: 1.2.14
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Globalization;

partial class ThisAssembly
{
    public static partial class Git
    {
        /// <summary>
        /// => @"[pending build]"
        /// </summary>
        public const string Commit = @"[pending build]";
    }
}
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     ThisAssembly.Constants: 1.2.14
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Globalization;

partial class ThisAssembly
{
    public static partial class Git
    {
        /// <summary>
        /// => @"[pending build]"
        /// </summary>
        public const string Root = @"[pending build]";
    }
}
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     ThisAssembly.Constants: 1.2.14
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Globalization;

partial class ThisAssembly
{
    public static partial class Git
    {
        /// <summary>
        /// => @"[pending build]"
        /// </summary>
        public const string Sha = @"[pending build]";
    }
}
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     ThisAssembly.Constants: 1.2.14
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Globalization;

partial class ThisAssembly
{
    public static partial class Git
    {
        /// <summary>
        /// => @"[pending build]"
        /// </summary>
        public const string Url = @"[pending build]";
    }
}
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using System.Runtime.CompilerServices;

/// <summary>
/// Provides access to the current assembly information as pure constants, 
///  without requiring reflection.
/// </summary>
partial class ThisAssembly
{
    /// <summary>
    /// Gets the assembly metadata.
    /// </summary>
    [GeneratedCode("ThisAssembly.Metadata", "1.2.14")]
    [CompilerGenerated]
    public static partial class Metadata
    {
    }
}
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System.CodeDom.Compiler;
using System.Runtime.CompilerServices;

/// <summary>
/// Provides access to the current assembly information as pure constants, 
///  without requiring reflection.
/// </summary>
partial class ThisAssembly
{
    /// <summary>
    /// Gets the project properties.
    /// </summary>
    [GeneratedCode("ThisAssembly.Project", "1.2.14")]
    [CompilerGenerated]
    public static partial class Project
    {
        /// <summary>AssemblyName = RSCG_Version</summary>
        public const string AssemblyName = @"RSCG_Version";

        /// <summary>RootNamespace = RSCG_Version</summary>
        public const string RootNamespace = @"RSCG_Version";

        /// <summary>TargetFrameworkIdentifier = .NETCoreApp</summary>
        public const string TargetFrameworkIdentifier = @".NETCoreApp";

        /// <summary>TargetFrameworkMoniker = .NETCoreApp,Version=v7.0</summary>
        public const string TargetFrameworkMoniker = @".NETCoreApp,Version=v7.0";

        /// <summary>TargetFrameworkVersion = v7.0</summary>
        public const string TargetFrameworkVersion = @"v7.0";

    }
}
using System;
using System.IO;
using System.Linq;
using System.Reflection;

static class EmbeddedResource
{
    static readonly string baseDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "";

    public static string GetContent(string relativePath)
    {
        using var stream = GetStream(relativePath);
        using var reader = new StreamReader(stream);
        return reader.ReadToEnd();
    }

    public static byte[] GetBytes(string relativePath)
    {
        using var stream = GetStream(relativePath);
        var bytes = new byte[stream.Length];
        stream.Read(bytes, 0, bytes.Length);
        return bytes;
    }

    public static Stream GetStream(string relativePath)
    {
        var filePath = Path.Combine(baseDir, Path.GetFileName(relativePath));
        if (File.Exists(filePath))
            return File.OpenRead(filePath);

        var baseName = Assembly.GetExecutingAssembly().GetName().Name;
        var resourceName = relativePath
            .TrimStart('.')
            .Replace('/', '.')
            .Replace('\\', '.');

        var manifestResourceName = Assembly.GetExecutingAssembly()
            .GetManifestResourceNames().FirstOrDefault(x => x.EndsWith(resourceName));

        if (string.IsNullOrEmpty(manifestResourceName))
            throw new InvalidOperationException($"Did not find required resource ending in '{resourceName}' in assembly '{baseName}'.");

        return
            Assembly.GetExecutingAssembly().GetManifestResourceStream(manifestResourceName) ??
            throw new InvalidOperationException($"Did not find required resource '{manifestResourceName}' in assembly '{baseName}'.");
    }
}
using System.Collections.Concurrent;
using System.Resources;
using System.Runtime.CompilerServices;

/// <summary>
/// Provides access to the current assembly information as pure constants, 
///  without requiring reflection.
/// </summary>
partial class ThisAssembly
{
    /// <summary>
    /// Access the strings provided by resource files in the project.
    /// </summary>
    [CompilerGenerated]
    public static partial class Strings
    {
        static ConcurrentDictionary<string, ResourceManager> resourceManagers = new ConcurrentDictionary<string, ResourceManager>();

        static ResourceManager GetResourceManager(string resourceName)
            => resourceManagers.GetOrAdd(resourceName, name => new ResourceManager(name, typeof(Strings).Assembly));
    }
}

Code and pdf at

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

RSCG–ISourceGenerator porting to IIncrementalGenerator in 3 steps

Roslyn Source Code Generators (RSCG) have deprecated the ISourceGenerator  (roslyn/source-generators.md at main · dotnet/roslyn · GitHub )   vs the new interface IIncrementalGenerator , roslyn/incremental-generators.md at main · dotnet/roslyn · GitHub . That because of the idea of speed of generating code – and the idea of not generating twice the same code.

How is the implementation of IIncrementalGenerator , when you have already an ISourceGenerator  ?

I have moved the https://github.com/ignatandrei/rsCG_timeBombComment/ ( the generates code to transform comments / obsolete attribute as errors , after a time) and  https://github.com/ignatandrei/SkinnyControllersGenerator/ those are my findings

  1. Read the theory from https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md .  The ISourceGenerator was simpler to understand. After you read you can see how  the IIncrementalGenerator makes sense for increasing performance of RSCG.
  2. The code from ISourceGenerator  could be copy and paste to IIncrementalGenerator . The code from ISourceGenerator.Initialize belongs now to context.SyntaxProvider.CreateSyntaxProvider –> predicate , where the code that obtain the datas is written after this
  3. The real code that generates the new source code belong to context.RegisterSourceOutput

 

There are some problems

  1. Register a diagnostic occurs later  – could be fixed with Analyzers – see Incremental Roslyn Source Generators In .NET 6: Better Experience Through Roslyn Analyzers & Code Fixes – Part 2 – Thinktecture AG
  2. The additional files also occurs later – could be fixed by having a prefix in the file name in the order to not load all files content

Overall , this is a nicer way to wrote code ( although the learning curve is bigger). You can see the result at file RSCG_TimeBombComment\src\RSCG_TimeBombComment\RSCG_TimeBombComment\GenerateFromComments.cs vs RSCG_TimeBombComment\src\RSCG_TimeBombComment\RSCG_TimeBombComment\GenerateFromCommentsIncremental.cs from repo https://github.com/ignatandrei/rsCG_timeBombComment/

If you want to see more RSCG with the new method, keep an eye to https://ignatandrei.github.io/RSCG_Examples/v2/

 

 

File to CSharp Const

I was getting tired how many times I am reading from embedded resources – and finding it over and over the same code. So – what if I will transform the file into C# text ? Seems a work for Roslyn Source Code Generator – and the new one

IIncrementalGenerator

https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.md  , not the old ISourceGenerator https://learn.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview

So the code reads from additional files defined in .csproj

<ItemGroup>
<AdditionalFiles Include=”Second.gen.txt” />
<AdditionalFiles Include=”first.gen.txt” />
<AdditionalFiles Include=”test\Afirst.gen.txt” />
< /ItemGroup>

and then transforms in a const:

string x= MyAdditionalFiles.Second_gen_txt;

Now, how difficult is the code?

The first version was

public void Initialize(IncrementalGeneratorInitializationContext initContext)
{
IncrementalValuesProvider<AdditionalText> textFiles = initContext
    .AdditionalTextsProvider
    .Where(file => file.Path.Contains(".gen."));

// read their contents and save their name
IncrementalValuesProvider<(string name, string content)> namesAndContents = textFiles
    .Select((text, cancellationToken) => (name: Path.GetFileName(text.Path), content: text.GetText(cancellationToken)!.ToString()));
            
// generate a class that contains their values as const strings
initContext.RegisterSourceOutput(namesAndContents, (spc, nameAndContent) =>
{
                
    string nameString=nameAndContent.name
        .Replace(".","_")
        .Replace("-", "_")
        ;
        
    string[] lines = nameAndContent.content
        .Split('\n', '\r')
        .Where(it => it.Trim().Length > 0)
        .Select(it => it.Replace("\\", "\\\\"))
        .Select(it => it.Replace("\"", "\\\""))
        .Select(it => "\"" + it + "\\r\\n" + "\"")
        .ToArray();
    string content = string.Join("\r\n+", lines);
    string hint = $"MyAdditionalFiles.{nameAndContent.name}";
    var str = $@"
public static partial class MyAdditionalFiles
{{
//https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string                
public const string {nameString} =  {content};
}}";
    spc.AddSource(hint,str );
});
}

But it have performed poorly ( 3 minutes build for a file with 2MB ) . I was thinking that splitting into lines and replacing quotes and / was the faulty

So raw strings, https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/raw-string , to the help – the second version is

//v1
//string[] lines = nameAndContent.content
//    .Split('\n', '\r')
//    .Where(it => it.Trim().Length > 0)
//    .Select(it => it.Replace("\\","\\\\"))
//    .Select(it=>it.Replace("\"","\\\""))
//    .Select(it => "\"" + it +"\\r\\n"+ "\"")
//    .ToArray();
//string content = string.Join("\r\n+",lines);
//v2 => .net 7
string content=nameAndContent.content;       
//too much, but otherwise start counting quotes
var quotes = new string('"', 10);
content = quotes+"\r\n"+ content+"\r\n"+ quotes;

 

Additional details to be mentioned:

1.The Release with GitHUb Actions should also to be mentioned –the deployment to NUGET is a easy way now

2. Debugging is relative easy https://github.com/JoanComasFdz/dotnet-how-to-debug-source-generator-vs2022

3. It is a day of work to get rid of embedded files!

4. Does not work with binary files ( error with AdditionalFiles )

You can find the package at https://github.com/ignatandrei/RSCG_Utils .

DB2Code – part 8–closing

From now on the only work to be done is improving step by step the generating code. For example,

1. in the REST API , the code is accessing directly the database- should be an indirection layer

2. Should generate some mock classes to return data – instead of going to database ( or maybe EF In Memory is enough?)

3. Other GUI improvements

4. Generate other project types ( e.g. .NET MAUI ,  Blazor …)

But those are just small improvements  – the whole architecture of the project works and it is running fast to have functional code.

More , it can be customized at the needs of every programmer –  if they are familiar with t4 files.

However, the fact that a programmer could make very fast an application that generates code is a sign that in 20 years + the programming is in another paradigm ( not to mention ChatGPT …)

The final result is at https://marketplace.visualstudio.com/items?itemName=ignatandrei.databasetocode

Db2Code–part 6 – implementation details

Problem 1 More dbContexts

I have think that a user can have more than 1 DBContext / database implemented. If there was just only one , it were easy to add a partial to program.cs and register the database DI

services.AddDbContext<ApplicationDBContext>

in the partial .  However, if each database is generated, how to have this  ? The answer is   https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.moduleinitializerattribute?view=net-7.0

[ModuleInitializer]
    public static void AddMe()
    {
        Generated.UtilsControllers.registerContexts.Add(new RegisterApplicationDBContext());
    }

And in the WebAPI

foreach (IRegisterContext item in UtilsControllers.registerContexts)
         {
            typesContext.Add( item.AddServices(builder.Services, builder.Configuration));
         }

Problem 2 Create database if not exists

I want to let the user to create the database if it dows not exists. But how, if I do not know the name of the database ? The idea is to obtain the DBContext from the name and inject into the DI

builder.Services.AddTransient((ctx) =>
         {
             Func<string, DbContext?> a = (string dbName) =>
             {
                 var t = typesContext.First(it => it.Name == dbName);
                
                 var req = ctx.GetRequiredService(t);
                 if (req == null) return null;
                 return req as DbContext;
             };
             return a;
         });

And then obtain from the controller action

[HttpPost(“{dbName}”)]
    public async Task<bool> EnsureCreated([FromServices] Func<string, DbContext?> fact, string dbName)
    {
        var exists = AllDB.Singleton.ExistsDB(dbName);
        if (!exists)
        {
            throw new ArgumentException(“DB does not exists ” + dbName);
        }

       var req = fact(dbName);
        if(req == null)
            throw new ArgumentException(“service does not exists ” + dbName);

       return await req.Database.EnsureCreatedAsync();
    }

Problem 3 ; Generate the correct pasca case names for typescript properties

This was something difficult. But  –  I solved by simply add this

public class LowerCaseNamingPolicy : JsonNamingPolicy
{
    public override string ConvertName(string name)
    {
        if (string.IsNullOrWhiteSpace(name))
            return name;

        return name.ToLower();
    }
}

in order to have all with lowercase

builder.Services.AddControllers()
             .AddJsonOptions(c =>
             {
                 c.JsonSerializerOptions.PropertyNamingPolicy = new LowerCaseNamingPolicy();
             })
               .PartManager.ApplicationParts.Add(new AssemblyPart(assControllers)); ;
         ;

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.