RSCG – corecraft

RSCG – corecraft
 
 

name corecraft
nuget https://www.nuget.org/packages/corecraft/
link https://github.com/AlexNav73/CoreCraft
author

Decomposing properties and class into Domain Models. Seems however too complicated to use

 

This is how you can use corecraft .

The code that you start with is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
	<ItemGroup>
	  <None Remove="Person.model.json" />
	</ItemGroup>
	<ItemGroup>
	  <AdditionalFiles Include="Person.model.json">
	    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
	  </AdditionalFiles>
	</ItemGroup>
	<ItemGroup>
	  <PackageReference Include="CoreCraft" Version="0.6.0" />
	  <PackageReference Include="CoreCraft.Generators" Version="0.6.0">
	    <PrivateAssets>all</PrivateAssets>
	    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
	  </PackageReference>
	</ItemGroup>
</Project>


The code that you will use is


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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
	<PropertyGroup>
		<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
		<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
	</PropertyGroup>
	<ItemGroup>
	  <None Remove="Person.model.json" />
	</ItemGroup>
	<ItemGroup>
	  <AdditionalFiles Include="Person.model.json">
	    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
	  </AdditionalFiles>
	</ItemGroup>
	<ItemGroup>
	  <PackageReference Include="CoreCraft" Version="0.6.0" />
	  <PackageReference Include="CoreCraft.Generators" Version="0.6.0">
	    <PrivateAssets>all</PrivateAssets>
	    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
	  </PackageReference>
	</ItemGroup>
</Project>



using CoreCraft;
using CoreCraft.ChangesTracking;
using CoreCraft.Subscription;
using Json2Code.Person;
using Json2Code.Person.Entities;
var model = new DomainModel(new[] { new Json2Code.Person.PersonShardModelShard() });

// Subscribe to Items collection change events 
using var subscription = model.For<IPersonShardChangesFrame>()
    .With(x => x.Persons)
    .Subscribe(OnItemChanged);

// Observe changes
void OnItemChanged(Change<ICollectionChangeSet<Person, PersonProperties>> changes)
{
    foreach (var c in changes.Hunk)
    {
        Console.WriteLine($"Entity [{c.Entity}] has been {c.Action}ed.");
        Console.WriteLine($"   Old data: {c.OldData}");
        Console.WriteLine($"   New data: {c.NewData}");
    }
}


await model.Run<IMutablePersonShardModelShard> (
    (shard, _) =>
    {
        shard.Persons.Add(new() { FirstName = "A", LastName = "B" });
        //shard.Persons.Remove(shard.Persons.First());
    });
await model.Run<IMutablePersonShardModelShard>(
    (shard, _) =>
    {        
        shard.Persons.Modify(shard.Persons.First(), p => p with { FirstName = "C" });
    });

await model.Run<IMutablePersonShardModelShard>(
    (shard, _) =>
    {
        shard.Persons.Remove(shard.Persons.First());
    });



Console.WriteLine("Press any key to exit...");
Console.ReadKey();



{
  "shards": [
    {
      "name": "PersonShard",
      "entities": [
        {
          "name": "Person",
          "properties": [
            {
              "name": "FirstName",
              "type": "string",
              "defaultValue": "\"Andrei\""
            },
            {
              "name": "LastName",
              "type": "string",
              "defaultValue": "\"Ignat\""
            }
          ]
        }
      ],
      "collections": [
        {
          "name": "Persons",
          "entityType": "Person"
        }
      ],
      "relations": []
    }
  ]
}

 

The code that is generated is


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

#nullable enable

namespace Json2Code.Person
{
    using CoreCraft.Core;
    using CoreCraft.ChangesTracking;
    using CoreCraft.Persistence;
    using Json2Code.Person.Entities;

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public interface IPersonShardModelShard : IModelShard
    {
        ICollection<Person, PersonProperties> Persons { get; }

    }

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public interface IMutablePersonShardModelShard : IModelShard
    {
        IMutableCollection<Person, PersonProperties> Persons { get; }

    }

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
    internal static class PersonShardModelShardInfo
    {
        public static readonly CollectionInfo PersonsInfo = new("PersonShard", "Persons", new PropertyInfo[] { new("FirstName", typeof(string), false), new("LastName", typeof(string), false) });

    }

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
    internal sealed partial class PersonShardModelShard : IPersonShardModelShard
    {
        public const string PersonsId = "Json2Code.Person.PersonShard.Persons";

        public PersonShardModelShard()
        {
            Persons = new Collection<Person, PersonProperties>(
                PersonsId,
                static id => new Person(id),
                static () => new PersonProperties());

        }

        internal PersonShardModelShard(IMutablePersonShardModelShard mutable)
        {
            Persons = ((IMutableState<ICollection<Person, PersonProperties>>)mutable.Persons).AsReadOnly();

        }

        public ICollection<Person, PersonProperties> Persons { get; init; } = null!;

    }

    internal sealed partial class PersonShardModelShard : IReadOnlyState<IMutablePersonShardModelShard>
    {
        public IMutablePersonShardModelShard AsMutable(global::System.Collections.Generic.IEnumerable<IFeature> features)
        {
            var persons = (IMutableCollection<Person, PersonProperties>)Persons;


            foreach (var feature in features)
            {
                persons = feature.Decorate(this, persons);

            }

            return new MutablePersonShardModelShard()
            {
                Persons = persons,

            };
        }
    }

    internal sealed partial class PersonShardModelShard : ICanBeSaved
    {
        public void Save(IRepository repository)
        {
            repository.Save(PersonShardModelShardInfo.PersonsInfo, Persons);

        }
    }

    internal sealed partial class PersonShardModelShard : IFeatureContext
    {
        IChangesFrame IFeatureContext.GetOrAddFrame(IMutableModelChanges modelChanges)
        {
            return modelChanges.Register(static () => new PersonShardChangesFrame());
        }
    }

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    public interface IPersonShardChangesFrame : IChangesFrame
    {
        ICollectionChangeSet<Person, PersonProperties> Persons { get; }

    }

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
    internal sealed class PersonShardChangesFrame : IPersonShardChangesFrame, IChangesFrameEx, ICanBeSaved
    {
        public PersonShardChangesFrame()
        {
            Persons = new CollectionChangeSet<Person, PersonProperties>(PersonShardModelShard.PersonsId);

        }

        public ICollectionChangeSet<Person, PersonProperties> Persons { get; private set; }


        ICollectionChangeSet<TEntity, TProperty>? IChangesFrame.Get<TEntity, TProperty>(ICollection<TEntity, TProperty> collection)
        {
            if (Persons.Id == collection.Id) return Persons as ICollectionChangeSet<TEntity, TProperty>;

            throw new System.InvalidOperationException("Unable to find collection's changes set");
        }

        IRelationChangeSet<TParent, TChild>? IChangesFrame.Get<TParent, TChild>(IRelation<TParent, TChild> relation)
        {

            throw new System.InvalidOperationException($"Unable to find relation's change set");
        }

        IChangesFrame IChangesFrame.Invert()
        {
            return new PersonShardChangesFrame()
            {
                Persons = Persons.Invert(),

            };
        }

        public void Apply(IModel model)
        {
            var modelShard = model.Shard<IMutablePersonShardModelShard>();

            Persons.Apply(modelShard.Persons);
        }

        public bool HasChanges()
        {
            return Persons.HasChanges();
        }

        public IChangesFrame Merge(IChangesFrame frame)
        {
            var typedFrame = (PersonShardChangesFrame)frame;

            return new PersonShardChangesFrame()
            {
                Persons = Persons.Merge(typedFrame.Persons),

            };
        }

        public void Save(IRepository repository)
        {
            repository.Save(PersonShardModelShardInfo.PersonsInfo, Persons);

        }

    }

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
    internal sealed class MutablePersonShardModelShard : IMutablePersonShardModelShard, IMutableState<IPersonShardModelShard>, ICanBeLoaded
    {
        public IMutableCollection<Person, PersonProperties> Persons { get; init; } = null!;


        public IPersonShardModelShard AsReadOnly()
        {
            return new PersonShardModelShard(this);
        }

        public void Load(IRepository repository)
        {
            repository.Load(PersonShardModelShardInfo.PersonsInfo, Persons);

        }
    }

}

namespace Json2Code.Person.Entities
{
    using CoreCraft.Core;

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
    public sealed record Person(global::System.Guid Id) : Entity(Id)
    {
        internal Person() : this(global::System.Guid.NewGuid())
        {
        }
    }

    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("C# Source Generator", "1.0.0.0")]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute()]
    public sealed partial record PersonProperties : Properties
    {
        public PersonProperties()
        {
            FirstName = "Andrei";
            LastName = "Ignat";
        }

        public string FirstName { get; init; }
        public string LastName { get; init; }

#if NET5_0_OR_GREATER
        public override PersonProperties ReadFrom(IPropertiesBag bag)
#else
        public override Properties ReadFrom(IPropertiesBag bag)
#endif
        {
            return new PersonProperties()
            {
                FirstName = bag.Read<string>("FirstName"),
                LastName = bag.Read<string>("LastName"),
            };
        }

        public override void WriteTo(IPropertiesBag bag)
        {
            bag.Write("FirstName", FirstName);
            bag.Write("LastName", LastName);
        }

    }


}

Code and pdf at

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

RSCG – sourcedepend

RSCG – sourcedepend
 
 

name sourcedepend
nuget https://www.nuget.org/packages/sourcedepend/
link https://github.com/crwsolutions/sourcedepend
author Colin Wilmans

Generating constructor for DI

 

This is how you can use sourcedepend .

The code that you start with is


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

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

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

	<ItemGroup>
	  <PackageReference Include="SourceDepend" Version="0.3.0" />
	</ItemGroup>

</Project>


The code that you will use is


using CtorDemo;

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

Console.WriteLine(p.FullName());



namespace CtorDemo;
internal partial class Person
{
    [Dependency]
    public readonly string? FirstName;
    [Dependency]
    public readonly string? LastName;
    
    public string FullName() => $"{FirstName} {LastName}";

    partial void PostConstruct()
    {
        Console.WriteLine("Person constructed");
    }
    partial void PreConstruct()
    {
        Console.WriteLine("Person constructing");
    }

}


 

The code that is generated is

// <auto-generated />

/// <summary>
/// Injects this item in the constructor. This will also highjack your constructor, so if you have any construct business, use PreConstruct() or PostConstruct() methods.
/// </summary>
/// <remarks>
/// Make sure your class is partial.
/// </remarks>
[System.AttributeUsage(System.AttributeTargets.Field | System.AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
[System.Diagnostics.Conditional("DependencyGenerator_DEBUG")]
internal sealed class DependencyAttribute : System.Attribute
{
    internal DependencyAttribute(string alternativePropertyName = null) { }
}

// <auto-generated/>
#pragma warning disable
#nullable enable
namespace CtorDemo
{
    /// <inheritdoc/>
    internal partial class Person
    {
        public Person(string? FirstName, string? LastName)
        {
            PreConstruct();

            this.FirstName = FirstName;
            this.LastName = LastName;

            PostConstruct();
        }

        partial void PreConstruct();
        partial void PostConstruct();
    }
}

Code and pdf at

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

RSCG – OptionToStringGenerator

RSCG – OptionToStringGenerator
 
 

name OptionToStringGenerator
nuget https://www.nuget.org/packages/Seekatar.OptionToStringGenerator/
link https://github.com/Seekatar/OptionToStringGenerator
author Jim W

Generating similar ToString method for classes with many properties. It can also generate for external classes.

 

This is how you can use OptionToStringGenerator .

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


The code that you will use is


using Class2String;
using Seekatar.OptionToStringGenerator;
var p = new Person();
p.FirstName = "Andrei";
p.LastName = "Ignat";
p.Age = 50;
Console.WriteLine(p.OptionsToString());    


using Seekatar.OptionToStringGenerator;

namespace Class2String;

[OptionsToString]
internal class Person
{
    [OutputMask(PrefixLen = 3)]
    public string? FirstName { get; set; }
    [OutputMask(SuffixLen = 3)]
    public string? LastName { get; set; }

    public string FUllName => $"{FirstName} {LastName}";

    [OutputIgnore]
    public int Age { get; set; }
}

 

The code that is generated is

#nullable enable
using static Seekatar.Mask;
namespace Seekatar.OptionToStringGenerator
{
    public static partial class ClassExtensions
    {
        internal static string OptionsToString(this Class2String.Person o)
        {
            return $@"Class2String.Person:
  FirstName : {Format(o?.FirstName,prefixLen:3,suffixLen:0)}
  LastName  : {Format(o?.LastName,prefixLen:0,suffixLen:3)}
  FUllName  : {Format(o?.FUllName)}
";
        }
    }
}

Code and pdf at

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

RSCG – cachesourcegenerator

RSCG – cachesourcegenerator
 
 

name cachesourcegenerator
nuget https://www.nuget.org/packages/cachesourcegenerator/
link https://github.com/jeppevammenkristensen/cachesourcegenerator
author Jeppe Roi Kristensen

Caching methods results

 

This is how you can use cachesourcegenerator .

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="CacheSourceGenerator" Version="0.4.1" />
    <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
  </ItemGroup>
	<ItemGroup>
		<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
	</ItemGroup>
 <PropertyGroup>
        <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
        <CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GX</CompilerGeneratedFilesOutputPath>
    </PropertyGroup>
</Project>


The code that you will use is


using CacheDemo;
using Microsoft.Extensions.Caching.Memory;
var f=new FibTest(new MemoryCache(new MemoryCacheOptions()));
Console.WriteLine(f.FibMemo(5));
Console.WriteLine("and now with cache hit:");
Console.WriteLine(f.FibMemo(5));



using Microsoft.Extensions.Caching.Memory;
using CacheSourceGenerator;
namespace CacheDemo;
internal partial class FibTest
{
    private readonly IMemoryCache _memoryCache;

    public FibTest(IMemoryCache memoryCache)
    {
        _memoryCache = memoryCache;
    }
    void ProcessCacheEntry(ICacheEntry entry)
    {
        entry.SlidingExpiration = TimeSpan.FromMinutes(2);
    }

    [GenerateMemoryCache(MethodName = "FibMemo", CacheEnricherProcessor = nameof(ProcessCacheEntry))]
    public int Fib(int n)
    {
        if (n <= 1)
        {
            return n;
        }
        Console.WriteLine($"Calculating Fib({n})");
        //return Fib(n - 1) + Fib(n - 2);
        return FibMemo(n - 1) + FibMemo(n - 2);
    }
}

 

The code that is generated is

#nullable enable
//autogenerated
using Microsoft.Extensions.Caching.Memory;
using CacheSourceGenerator;
using System;

namespace CacheDemo;
internal partial class FibTest
{
    public int FibMemo(int n)
    {
        var _key_ = new
        {
            _MethodName = "Fib",
            _ClassName = "FibTest",
            n
        };
        IMemoryCache _cache_ = _memoryCache;
        var _result_ = _cache_.GetOrCreate(_key_, _entry_ =>
        {
            ProcessCacheEntry(_entry_);
            OnCallingFib(n);
            var _callResult_ = Fib(n);
            OnCalledFib(n, _callResult_);
            ;
            return _callResult_;
        });
        return _result_;
    }

    public void FibMemo_Evict(int n)
    {
        var _key_ = new
        {
            _MethodName = "Fib",
            _ClassName = "FibTest",
            n
        };
        IMemoryCache _cache_ = _memoryCache;
        _cache_.Remove(_key_);
    }

    partial void OnCallingFib(int n);
    partial void OnCalledFib(int n, int _returned_);
}

// <auto-generated/>
#nullable enable
namespace CacheSourceGenerator
{
    [System.AttributeUsage(System.AttributeTargets.Method)]
    public class GenerateMemoryCacheAttribute : System.Attribute
    {
       /// <summary>
       /// The name of the generated cache method 
       /// </summary>
       public string MethodName { get;init; } = default!;
       
       /// <summary>
       /// The name of a method in the current class that takes
       /// an CacheEntry and processes it 
       /// </summary>
       public string? CacheEnricherProcessor { get;set; }
       
       
       /// <summary>
        /// The name of a method in the current class that can 
        /// generate a custom cache key. The method must take the same parameters
        /// as the method being decorated. But can return any type.
        /// </summary>
       public string? KeyGenerator {get;set;}
       
       /// <summary>
       /// Set this to true to not generate an evict method
       /// </summary>
       public bool SuppressEvictMethod {get;set;}
    }
}
// <auto-generated/>
#nullable enable
namespace CacheSourceGenerator
{
    [System.AttributeUsage(System.AttributeTargets.Parameter)]
    public class IgnoreKeyAttribute : System.Attribute
    {
        
    }
}

Code and pdf at

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

RSCG – jab

RSCG – jab
 
 

name jab
nuget https://www.nuget.org/packages/jab/
link https://github.com/pakrym/jab
author Pavel Krymets

generating DI code

 

This is how you can use jab .

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


The code that you will use is


using InjectDemo;
using Jab;
MyServiceProvider sc = new();
//var con = sc.GetService<DatabaseCon>();
var db = sc.GetService<IDatabase>();
db.Open();


[ServiceProvider]
//[Transient(typeof(DatabaseCon), typeof(DatabaseCon))]
[Transient(typeof(IDatabase), typeof(DatabaseCon))]
internal partial class MyServiceProvider { }


namespace InjectDemo;

internal class Database : IDatabase
{
    private readonly DatabaseCon con;

    public Database(DatabaseCon con)
    {
        this.con = con;
    }
    public void Open()
    {
        Console.WriteLine($"open {con.Connection}");
    }

}





namespace InjectDemo;

internal class DatabaseCon: IDatabase
{
    public string? Connection { get; set; }
    public void Open()
    {
        Console.WriteLine("open" + Connection);
    }
}



 

The code that is generated is

// <auto-generated/>

#if !JAB_ATTRIBUTES_REFERENCED || JAB_ATTRIBUTES_PACKAGE

using System;
using System.Threading.Tasks;

#nullable enable

namespace Jab
{
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class ServiceProviderAttribute: Attribute
    {
        public Type[]? RootServices { get; set; }
    }

    [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class ServiceProviderModuleAttribute: Attribute
    {
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class ImportAttribute: Attribute
    {
        public Type ModuleType { get; }

        public ImportAttribute(Type moduleType)
        {
            ModuleType = moduleType;
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class SingletonAttribute: Attribute
    {
        public Type ServiceType { get; }

        public string? Name { get; set; }

        public Type? ImplementationType { get; }

        public string? Instance { get; set; }

        public string? Factory { get; set; }

        public SingletonAttribute(Type serviceType)
        {
            ServiceType = serviceType;
        }

        public SingletonAttribute(Type serviceType, Type implementationType)
        {
            ServiceType = serviceType;
            ImplementationType = implementationType;
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class TransientAttribute : Attribute
    {
        public Type ServiceType { get; }
        public string? Name { get; set; }

        public Type? ImplementationType { get; }

        public string? Factory { get; set; }

        public TransientAttribute(Type serviceType)
        {
            ServiceType = serviceType;
        }

        public TransientAttribute(Type serviceType, Type implementationType)
        {
            ServiceType = serviceType;
            ImplementationType = implementationType;
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class ScopedAttribute : Attribute
    {
        public Type ServiceType { get; }
        public string? Name { get; set; }

        public Type? ImplementationType { get; }

        public string? Factory { get; set; }

        public ScopedAttribute(Type serviceType)
        {
            ServiceType = serviceType;
        }

        public ScopedAttribute(Type serviceType, Type implementationType)
        {
            ServiceType = serviceType;
            ImplementationType = implementationType;
        }
    }


    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
        class FromNamedServicesAttribute : Attribute
    {
        public string? Name { get; set; }

        public FromNamedServicesAttribute(string name)
        {
            Name = name;
        }
    }

#if GENERIC_ATTRIBUTES
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class ImportAttribute<TModule> : ImportAttribute
    {
        public ImportAttribute() : base(typeof(TModule))
        {
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class TransientAttribute<TService> : TransientAttribute
    {
        public TransientAttribute() : base(typeof(TService))
        {
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class TransientAttribute<TService, TImpl> : TransientAttribute where TImpl: TService
    {
        public TransientAttribute() : base(typeof(TService), typeof(TImpl))
        {
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class ScopedAttribute<TService> : ScopedAttribute
    {
        public ScopedAttribute() : base(typeof(TService))
        {
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class ScopedAttribute<TService, TImpl> : ScopedAttribute where TImpl: TService
    {
        public ScopedAttribute() : base(typeof(TService), typeof(TImpl))
        {
        }
    }


    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class SingletonAttribute<TService> : SingletonAttribute
    {
        public SingletonAttribute() : base(typeof(TService))
        {
        }
    }

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = true)]
#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    class SingletonAttribute<TService, TImpl> : SingletonAttribute where TImpl: TService
    {
        public SingletonAttribute() : base(typeof(TService), typeof(TImpl))
        {
        }
    }

#endif

#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    interface IServiceProvider<T>
    {
        T GetService();
    }

#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    interface INamedServiceProvider<T>
    {
        T GetService(string name);
    }

#if JAB_ATTRIBUTES_PACKAGE
    public
#else
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", null)]
    internal
#endif
    static class JabHelpers
    {
        public static InvalidOperationException CreateServiceNotFoundException<T>(string? name = null) =>
            CreateServiceNotFoundException(typeof(T), name);
        public static InvalidOperationException CreateServiceNotFoundException(Type type, string? name = null) =>
            new InvalidOperationException(
                name != null ?
                    $"Service with type {type} and name {name} not registered" :
                    $"Service with type {type} not registered");
    }
}

#endif

// <auto-generated/>

#nullable enable

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using Jab;

using static Jab.JabHelpers;
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Jab", "0.10.2.0")]
internal partial class MyServiceProvider : global::System.IDisposable,
   System.IAsyncDisposable,
   global::System.IServiceProvider,
   IServiceProvider<InjectDemo.DatabaseCon>,
   IServiceProvider<InjectDemo.IDatabase>,
   IServiceProvider<System.IServiceProvider>
{
    private Scope? _rootScope;
    
    InjectDemo.DatabaseCon IServiceProvider<InjectDemo.DatabaseCon>.GetService()
    {
        InjectDemo.DatabaseCon service = new InjectDemo.DatabaseCon();
        TryAddDisposable(service);
        return service;
    }
    
    InjectDemo.IDatabase IServiceProvider<InjectDemo.IDatabase>.GetService()
    {
        InjectDemo.DatabaseCon service = new InjectDemo.DatabaseCon();
        TryAddDisposable(service);
        return service;
    }
    
    System.IServiceProvider IServiceProvider<System.IServiceProvider>.GetService()
    {
        return this;
    }
    
    object? global::System.IServiceProvider.GetService(global::System.Type type){
        if (type == typeof(InjectDemo.DatabaseCon)) return this.GetService<InjectDemo.DatabaseCon>();
        if (type == typeof(InjectDemo.IDatabase)) return this.GetService<InjectDemo.IDatabase>();
        if (type == typeof(System.IServiceProvider)) return this.GetService<System.IServiceProvider>();
        return null;
    }
    
    private global::System.Collections.Generic.List<object>? _disposables;
    
    private void TryAddDisposable(object? value){
        if (value is global::System.IDisposable || value is System.IAsyncDisposable)
        lock (this){
            (_disposables ??= new global::System.Collections.Generic.List<object>()).Add(value);
        }
    }
    
    public void Dispose(){
        void TryDispose(object? value) => (value as IDisposable)?.Dispose();
        
        TryDispose(_rootScope);
        if (_disposables != null){
            foreach (var service in _disposables){
                TryDispose(service);
            }
        }
    }
    
    public async global::System.Threading.Tasks.ValueTask DisposeAsync(){
        global::System.Threading.Tasks.ValueTask TryDispose(object? value){
            if (value is System.IAsyncDisposable asyncDisposable){
                return asyncDisposable.DisposeAsync();
            }
            else if (value is global::System.IDisposable disposable){
                disposable.Dispose();
            }
            return default;
        }
        
        await TryDispose(_rootScope);
        if (_disposables != null){
            foreach (var service in _disposables){
                await TryDispose(service);
            }
        }
    }
    
    [DebuggerHidden]
    public T GetService<T>() => this is IServiceProvider<T> provider ? provider.GetService() : throw CreateServiceNotFoundException<T>();
    
    [DebuggerHidden]
    public T GetService<T>(string name) => this is INamedServiceProvider<T> provider ? provider.GetService(name) : throw CreateServiceNotFoundException<T>(name);
    
    public Scope CreateScope() => new Scope(this);
    
    public partial class Scope : global::System.IDisposable,
       System.IAsyncDisposable,
       global::System.IServiceProvider,
       IServiceProvider<InjectDemo.DatabaseCon>,
       IServiceProvider<InjectDemo.IDatabase>,
       IServiceProvider<System.IServiceProvider>    
    {
        
        private MyServiceProvider _root;
        
        public Scope(MyServiceProvider root){
            _root = root;
        }
        
        [DebuggerHidden]
        public T GetService<T>() => this is IServiceProvider<T> provider ? provider.GetService() : throw CreateServiceNotFoundException<T>();
        
        [DebuggerHidden]
        public T GetService<T>(string name) => this is INamedServiceProvider<T> provider ? provider.GetService(name) : throw CreateServiceNotFoundException<T>(name);
        
        InjectDemo.DatabaseCon IServiceProvider<InjectDemo.DatabaseCon>.GetService(){
            InjectDemo.DatabaseCon service = new InjectDemo.DatabaseCon();
            TryAddDisposable(service);
            return service;
        }
        
        InjectDemo.IDatabase IServiceProvider<InjectDemo.IDatabase>.GetService(){
            InjectDemo.DatabaseCon service = new InjectDemo.DatabaseCon();
            TryAddDisposable(service);
            return service;
        }
        
        System.IServiceProvider IServiceProvider<System.IServiceProvider>.GetService(){
            return this;
        }
        
        object? global::System.IServiceProvider.GetService(global::System.Type type){
            if (type == typeof(InjectDemo.DatabaseCon)) return this.GetService<InjectDemo.DatabaseCon>();
            if (type == typeof(InjectDemo.IDatabase)) return this.GetService<InjectDemo.IDatabase>();
            if (type == typeof(System.IServiceProvider)) return this.GetService<System.IServiceProvider>();
            return null;
        }
        
        private global::System.Collections.Generic.List<object>? _disposables;
        
        private void TryAddDisposable(object? value){
            if (value is global::System.IDisposable || value is System.IAsyncDisposable)
            lock (this){
                (_disposables ??= new global::System.Collections.Generic.List<object>()).Add(value);
            }
        }
        
        public void Dispose(){
            void TryDispose(object? value) => (value as IDisposable)?.Dispose();
            
            if (_disposables != null){
                foreach (var service in _disposables){
                    TryDispose(service);
                }
            }
        }
        
        public async global::System.Threading.Tasks.ValueTask DisposeAsync(){
            global::System.Threading.Tasks.ValueTask TryDispose(object? value){
                if (value is System.IAsyncDisposable asyncDisposable){
                    return asyncDisposable.DisposeAsync();
                }
                else if (value is global::System.IDisposable disposable){
                    disposable.Dispose();
                }
                return default;
            }
            
            if (_disposables != null){
                foreach (var service in _disposables){
                    await TryDispose(service);
                }
            }
        }
        
    }
    private Scope GetRootScope(){
        if (_rootScope == default)
        lock (this)
        if (_rootScope == default){
            _rootScope = CreateScope();
        }
        return _rootScope;
    }
}

Code and pdf at

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

RSCG – FunicularSwitch

RSCG – FunicularSwitch
 
 

name FunicularSwitch
nuget https://www.nuget.org/packages/FunicularSwitch.Generators/
https://www.nuget.org/packages/FunicularSwitch
link https://github.com/bluehands/Funicular-Switch
author bluehands

Generating discriminated unions for C# 9.0 and above.

 

This is how you can use FunicularSwitch .

The code that you start with is


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

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

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

 
	<ItemGroup>
	  <PackageReference Include="FunicularSwitch" Version="5.0.1" />
	  <PackageReference Include="FunicularSwitch.Generators" Version="3.2.0">
	    <PrivateAssets>all</PrivateAssets>
	    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
	  </PackageReference>
	</ItemGroup>
</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;

[FunicularSwitch.Generators.ResultType(ErrorType = typeof(ErrorDetails))]
public abstract partial class ResultSave<T> { };

public class ErrorDetails
{
    
}



    //[FunicularSwitch.Generators.UnionType]
    //public abstract partial class ResultSave { };

    //public sealed partial record Success(int Value): ResultSave;
    //public sealed 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<int> Save(int i)
    {
        if (i == 0)
        {
            return new ResultSave<int>.Error_(new ErrorDetails());
        }
        return new ResultSave<int>.Ok_(i);
    }
}


 

The code that is generated is

using System;

// ReSharper disable once CheckNamespace
namespace FunicularSwitch.Generators
{
    [AttributeUsage(AttributeTargets.Enum)]
    sealed class ExtendedEnumAttribute : Attribute
    {
	    public EnumCaseOrder CaseOrder { get; set; } = EnumCaseOrder.AsDeclared;
	    public ExtensionAccessibility Accessibility { get; set; } = ExtensionAccessibility.Public;
    }
    
    enum EnumCaseOrder
    {
        Alphabetic,
        AsDeclared
    }

    /// <summary>
    /// Generate match methods for all enums defined in assembly that contains AssemblySpecifier.
    /// </summary>
    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
    class ExtendEnumsAttribute : Attribute
    {
	    public Type AssemblySpecifier { get; }
	    public EnumCaseOrder CaseOrder { get; set; } = EnumCaseOrder.AsDeclared;
	    public ExtensionAccessibility Accessibility { get; set; } = ExtensionAccessibility.Public;

	    public ExtendEnumsAttribute() => AssemblySpecifier = typeof(ExtendEnumsAttribute);

	    public ExtendEnumsAttribute(Type assemblySpecifier)
	    {
		    AssemblySpecifier = assemblySpecifier;
	    }
    }

    /// <summary>
    /// Generate match methods for Type. Must be enum.
    /// </summary>
    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
    class ExtendEnumAttribute : Attribute
    {
	    public Type Type { get; }

	    public EnumCaseOrder CaseOrder { get; set; } = EnumCaseOrder.AsDeclared;

	    public ExtensionAccessibility Accessibility { get; set; } = ExtensionAccessibility.Public;

	    public ExtendEnumAttribute(Type type)
	    {
		    Type = type;
	    }
    }

    enum ExtensionAccessibility
    {
	    Internal,
	    Public
    }
}
using System;

// ReSharper disable once CheckNamespace
namespace FunicularSwitch.Generators
{
	/// <summary>
	/// Mark an abstract partial type with a single generic argument with the ResultType attribute.
	/// This type from now on has Ok | Error semantics with map and bind operations.
	/// </summary>
    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
    sealed class ResultTypeAttribute : Attribute
    {
        public ResultTypeAttribute() => ErrorType = typeof(string);
        public ResultTypeAttribute(Type errorType) => ErrorType = errorType;

        public Type ErrorType { get; set; }
    }

    /// <summary>
    /// Mark a static method or a member method or you error type with the MergeErrorAttribute attribute.
    /// Static signature: TError -> TError -> TError. Member signature: TError -> TError
    /// We are now able to collect errors and methods like Validate, Aggregate, FirstOk that are useful to combine results are generated.
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, Inherited = false)]
    sealed class MergeErrorAttribute : Attribute
    {
    }

    /// <summary>
    /// Mark a static method with the ExceptionToError attribute.
    /// Signature: Exception -> TError
    /// This method is always called, when an exception happens in a bind operation.
    /// So a call like result.Map(i => i/0) will return an Error produced by the factory method instead of throwing the DivisionByZero exception.
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, Inherited = false)]
    sealed class ExceptionToError : Attribute
    {
    }
}
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using FunicularSwitch;

namespace Union
{
#pragma warning disable 1591
    public abstract partial class ResultSave
    {
        public static ResultSave<T> Error<T>(ErrorDetails details) => new ResultSave<T>.Error_(details);
        public static ResultSave<T> Ok<T>(T value) => new ResultSave<T>.Ok_(value);
        public bool IsError => GetType().GetGenericTypeDefinition() == typeof(ResultSave<>.Error_);
        public bool IsOk => !IsError;
        public abstract ErrorDetails? GetErrorOrDefault();

        public static ResultSave<T> Try<T>(Func<T> action, Func<Exception, ErrorDetails> formatError)
        {
            try
            {
                return action();
            }
            catch (Exception e)
            {
                return Error<T>(formatError(e));
            }
        }

        public static async Task<ResultSave<T>> Try<T>(Func<Task<T>> action, Func<Exception, ErrorDetails> formatError)
        {
            try
            {
                return await action();
            }
            catch (Exception e)
            {
                return Error<T>(formatError(e));
            }
        }
    }

    public abstract partial class ResultSave<T> : ResultSave, IEnumerable<T>
    {
        public static ResultSave<T> Error(ErrorDetails message) => Error<T>(message);
        public static ResultSave<T> Ok(T value) => Ok<T>(value);

        public static implicit operator ResultSave<T>(T value) => ResultSave.Ok(value);

        public static bool operator true(ResultSave<T> result) => result.IsOk;
        public static bool operator false(ResultSave<T> result) => result.IsError;

        public static bool operator !(ResultSave<T> result) => result.IsError;

        //just here to suppress warning, never called because all subtypes (Ok_, Error_) implement Equals and GetHashCode
        bool Equals(ResultSave<T> other) => this switch
        {
            Ok_ ok => ok.Equals((object)other),
            Error_ error => error.Equals((object)other),
            _ => throw new InvalidOperationException($"Unexpected type derived from {nameof(ResultSave<T>)}")
        };

        public override int GetHashCode() => this switch
        {
            Ok_ ok => ok.GetHashCode(),
            Error_ error => error.GetHashCode(),
            _ => throw new InvalidOperationException($"Unexpected type derived from {nameof(ResultSave<T>)}")
        };

        public override bool Equals(object? obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != this.GetType()) return false;
            return Equals((ResultSave<T>)obj);
        }

        public static bool operator ==(ResultSave<T>? left, ResultSave<T>? right) => Equals(left, right);

        public static bool operator !=(ResultSave<T>? left, ResultSave<T>? right) => !Equals(left, right);

        public void Match(Action<T> ok, Action<ErrorDetails>? error = null) => Match(
            v =>
            {
                ok.Invoke(v);
                return 42;
            },
            err =>
            {
                error?.Invoke(err);
                return 42;
            });

        public T1 Match<T1>(Func<T, T1> ok, Func<ErrorDetails, T1> error)
        {
            return this switch
            {
                Ok_ okResultSave => ok(okResultSave.Value),
                Error_ errorResultSave => error(errorResultSave.Details),
                _ => throw new InvalidOperationException($"Unexpected derived result type: {GetType()}")
            };
        }

        public async Task<T1> Match<T1>(Func<T, Task<T1>> ok, Func<ErrorDetails, Task<T1>> error)
        {
            return this switch
            {
                Ok_ okResultSave => await ok(okResultSave.Value).ConfigureAwait(false),
                Error_ errorResultSave => await error(errorResultSave.Details).ConfigureAwait(false),
                _ => throw new InvalidOperationException($"Unexpected derived result type: {GetType()}")
            };
        }

        public Task<T1> Match<T1>(Func<T, Task<T1>> ok, Func<ErrorDetails, T1> error) =>
            Match(ok, e => Task.FromResult(error(e)));

        public async Task Match(Func<T, Task> ok)
        {
            if (this is Ok_ okResultSave) await ok(okResultSave.Value).ConfigureAwait(false);
        }

        public T Match(Func<ErrorDetails, T> error) => Match(v => v, error);

        public ResultSave<T1> Bind<T1>(Func<T, ResultSave<T1>> bind)
        {
            switch (this)
            {
                case Ok_ ok:
	                try
	                {
		                return bind(ok.Value);
	                }
	                // ReSharper disable once RedundantCatchClause
#pragma warning disable CS0168 // Variable is declared but never used
	                catch (Exception e)
#pragma warning restore CS0168 // Variable is declared but never used
	                {
		                throw; //createGenericErrorResult
	                }
                case Error_ error:
                    return error.Convert<T1>();
                default:
                    throw new InvalidOperationException($"Unexpected derived result type: {GetType()}");
            }
        }

        public async Task<ResultSave<T1>> Bind<T1>(Func<T, Task<ResultSave<T1>>> bind)
        {
            switch (this)
            {
                case Ok_ ok:
	                try
	                {
		                return await bind(ok.Value).ConfigureAwait(false);
	                }
	                // ReSharper disable once RedundantCatchClause
#pragma warning disable CS0168 // Variable is declared but never used
	                catch (Exception e)
#pragma warning restore CS0168 // Variable is declared but never used
	                {
		                throw; //createGenericErrorResult
	                }
                case Error_ error:
                    return error.Convert<T1>();
                default:
                    throw new InvalidOperationException($"Unexpected derived result type: {GetType()}");
            }
        }

        public ResultSave<T1> Map<T1>(Func<T, T1> map)
            => Bind(value => Ok(map(value)));

        public Task<ResultSave<T1>> Map<T1>(Func<T, Task<T1>> map)
            => Bind(async value => Ok(await map(value).ConfigureAwait(false)));

        public T? GetValueOrDefault()
	        => Match(
		        v => (T?)v,
		        _ => default
	        );

        public T GetValueOrDefault(Func<T> defaultValue)
	        => Match(
		        v => v,
		        _ => defaultValue()
	        );

        public T GetValueOrDefault(T defaultValue)
	        => Match(
		        v => v,
		        _ => defaultValue
	        );

        public T GetValueOrThrow()
            => Match(
                v => v,
                details => throw new InvalidOperationException($"Cannot access error result value. Error: {details}"));

        public IEnumerator<T> GetEnumerator() => Match(ok => new[] { ok }, _ => Enumerable.Empty<T>()).GetEnumerator();

        public override string ToString() => Match(ok => $"Ok {ok?.ToString()}", error => $"Error {error}");
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

        public sealed partial class Ok_ : ResultSave<T>
        {
            public T Value { get; }

            public Ok_(T value) => Value = value;

            public override ErrorDetails? GetErrorOrDefault() => null;

            public bool Equals(Ok_? other)
            {
                if (ReferenceEquals(null, other)) return false;
                if (ReferenceEquals(this, other)) return true;
                return EqualityComparer<T>.Default.Equals(Value, other.Value);
            }

            public override bool Equals(object? obj)
            {
                if (ReferenceEquals(null, obj)) return false;
                if (ReferenceEquals(this, obj)) return true;
                return obj is Ok_ other && Equals(other);
            }

            public override int GetHashCode() => Value == null ? 0 : EqualityComparer<T>.Default.GetHashCode(Value);

            public static bool operator ==(Ok_ left, Ok_ right) => Equals(left, right);

            public static bool operator !=(Ok_ left, Ok_ right) => !Equals(left, right);
        }

        public sealed partial class Error_ : ResultSave<T>
        {
            public ErrorDetails Details { get; }

            public Error_(ErrorDetails details) => Details = details;

            public ResultSave<T1>.Error_ Convert<T1>() => new ResultSave<T1>.Error_(Details);

            public override ErrorDetails? GetErrorOrDefault() => Details;

            public bool Equals(Error_? other)
            {
                if (ReferenceEquals(null, other)) return false;
                if (ReferenceEquals(this, other)) return true;
                return Equals(Details, other.Details);
            }

            public override bool Equals(object? obj)
            {
                if (ReferenceEquals(null, obj)) return false;
                if (ReferenceEquals(this, obj)) return true;
                return obj is Error_ other && Equals(other);
            }

            public override int GetHashCode() => Details.GetHashCode();

            public static bool operator ==(Error_ left, Error_ right) => Equals(left, right);

            public static bool operator !=(Error_ left, Error_ right) => !Equals(left, right);
        }

    }

    public static partial class ResultSaveExtension
    {
        #region bind

        public static async Task<ResultSave<T1>> Bind<T, T1>(
            this Task<ResultSave<T>> result,
            Func<T, ResultSave<T1>> bind)
            => (await result.ConfigureAwait(false)).Bind(bind);

        public static async Task<ResultSave<T1>> Bind<T, T1>(
            this Task<ResultSave<T>> result,
            Func<T, Task<ResultSave<T1>>> bind)
            => await (await result.ConfigureAwait(false)).Bind(bind).ConfigureAwait(false);

        #endregion

        #region map

        public static async Task<ResultSave<T1>> Map<T, T1>(
            this Task<ResultSave<T>> result,
            Func<T, T1> map)
            => (await result.ConfigureAwait(false)).Map(map);

        public static Task<ResultSave<T1>> Map<T, T1>(
            this Task<ResultSave<T>> result,
            Func<T, Task<T1>> bind)
            => Bind(result, async v => ResultSave.Ok(await bind(v).ConfigureAwait(false)));

        public static ResultSave<T> MapError<T>(this ResultSave<T> result, Func<ErrorDetails, ErrorDetails> mapError) =>
            result.Match(ok => ok, error => ResultSave.Error<T>(mapError(error)));

        #endregion

        #region match

        public static async Task<T1> Match<T, T1>(
            this Task<ResultSave<T>> result,
            Func<T, Task<T1>> ok,
            Func<ErrorDetails, Task<T1>> error)
            => await (await result.ConfigureAwait(false)).Match(ok, error).ConfigureAwait(false);

        public static async Task<T1> Match<T, T1>(
            this Task<ResultSave<T>> result,
            Func<T, Task<T1>> ok,
            Func<ErrorDetails, T1> error)
            => await (await result.ConfigureAwait(false)).Match(ok, error).ConfigureAwait(false);

        public static async Task<T1> Match<T, T1>(
            this Task<ResultSave<T>> result,
            Func<T, T1> ok,
            Func<ErrorDetails, T1> error)
            => (await result.ConfigureAwait(false)).Match(ok, error);

        #endregion

        public static ResultSave<T> Flatten<T>(this ResultSave<ResultSave<T>> result) => result.Bind(r => r);

        public static ResultSave<T1> As<T, T1>(this ResultSave<T> result, Func<ErrorDetails> errorTIsNotT1) =>
            result.Bind(r =>
            {
                if (r is T1 converted)
                    return converted;
                return ResultSave.Error<T1>(errorTIsNotT1());
            });

        public static ResultSave<T1> As<T1>(this ResultSave<object> result, Func<ErrorDetails> errorIsNotT1) =>
            result.As<object, T1>(errorIsNotT1);
        
        #region query-expression pattern
        
        public static ResultSave<T1> Select<T, T1>(this ResultSave<T> result, Func<T, T1> selector) => result.Map(selector);
        public static Task<ResultSave<T1>> Select<T, T1>(this Task<ResultSave<T>> result, Func<T, T1> selector) => result.Map(selector);
        
        public static ResultSave<T2> SelectMany<T, T1, T2>(this ResultSave<T> result, Func<T, ResultSave<T1>> selector, Func<T, T1, T2> resultSelector) => result.Bind(t => selector(t).Map(t1 => resultSelector(t, t1)));
        public static Task<ResultSave<T2>> SelectMany<T, T1, T2>(this Task<ResultSave<T>> result, Func<T, Task<ResultSave<T1>>> selector, Func<T, T1, T2> resultSelector) => result.Bind(t => selector(t).Map(t1 => resultSelector(t, t1)));
        public static Task<ResultSave<T2>> SelectMany<T, T1, T2>(this Task<ResultSave<T>> result, Func<T, ResultSave<T1>> selector, Func<T, T1, T2> resultSelector) => result.Bind(t => selector(t).Map(t1 => resultSelector(t, t1)));
        public static Task<ResultSave<T2>> SelectMany<T, T1, T2>(this ResultSave<T> result, Func<T, Task<ResultSave<T1>>> selector, Func<T, T1, T2> resultSelector) => result.Bind(t => selector(t).Map(t1 => resultSelector(t, t1)));

        #endregion
    }
}

namespace Union.Extensions
{
    public static partial class ResultSaveExtension
    {
        public static IEnumerable<T1> Choose<T, T1>(
            this IEnumerable<T> items,
            Func<T, ResultSave<T1>> choose,
            Action<ErrorDetails> onError)
            => items
                .Select(i => choose(i))
                .Choose(onError);

        public static IEnumerable<T> Choose<T>(
            this IEnumerable<ResultSave<T>> results,
            Action<ErrorDetails> onError)
            => results
                .Where(r =>
                    r.Match(_ => true, error =>
                    {
                        onError(error);
                        return false;
                    }))
                .Select(r => r.GetValueOrThrow());

        public static ResultSave<T> As<T>(this object item, Func<ErrorDetails> error) =>
            !(item is T t) ? ResultSave.Error<T>(error()) : t;

        public static ResultSave<T> NotNull<T>(this T? item, Func<ErrorDetails> error) =>
            item ?? ResultSave.Error<T>(error());

        public static ResultSave<string> NotNullOrEmpty(this string? s, Func<ErrorDetails> error)
            => string.IsNullOrEmpty(s) ? ResultSave.Error<string>(error()) : s!;

        public static ResultSave<string> NotNullOrWhiteSpace(this string? s, Func<ErrorDetails> error)
            => string.IsNullOrWhiteSpace(s) ? ResultSave.Error<string>(error()) : s!;

        public static ResultSave<T> First<T>(this IEnumerable<T> candidates, Func<T, bool> predicate, Func<ErrorDetails> noMatch) =>
            candidates
                .FirstOrDefault(i => predicate(i))
                .NotNull(noMatch);
    }
#pragma warning restore 1591
}

using System;

// ReSharper disable once CheckNamespace
namespace FunicularSwitch.Generators
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = false)]
    sealed class UnionTypeAttribute : Attribute
    {
        public CaseOrder CaseOrder { get; set; } = CaseOrder.Alphabetic;
        public bool StaticFactoryMethods { get; set; } = true;
    }

    enum CaseOrder
    {
        Alphabetic,
        AsDeclared,
        Explicit
    }

    [AttributeUsage(AttributeTargets.Class, Inherited = false)]
    sealed class UnionCaseAttribute : Attribute
    {
        public UnionCaseAttribute(int index) => Index = index;

        public int Index { get; }
    }
}

Code and pdf at

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

RSCG – CommandLine

RSCG – CommandLine
 
 

name CommandLine
nuget https://www.nuget.org/packages/DotMake.CommandLine/
link https://github.com/dotmake-build/command-line
author DotMake

Generating easy command line applications.

 

This is how you can use CommandLine .

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="DotMake.CommandLine" Version="1.8.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 DotMake.CommandLine;

Cli.Run(([CliArgument] string PersonName, int  Age) =>
{
    Console.WriteLine($@"Value for {nameof(PersonName)} parameter is '{PersonName}'");
    Console.WriteLine($@"Value for {nameof(Age)} parameter is '{Age}'");
});


Cli.Run(([CliArgument] int idData) =>
{
    Console.WriteLine($@"Value for {nameof(idData)} parameter is '{idData}'");
    
});

 

The code that is generated is

// <auto-generated />
// Generated by DotMake.CommandLine.SourceGeneration v1.8.0.0
// Roslyn (Microsoft.CodeAnalysis) v4.800.23.57201
// Generation: 1

namespace GeneratedCode
{
    /// <inheritdoc />
    [DotMake.CommandLine.CliCommandAttribute]
    public class CliCommandAsDelegate_1ra93x8 : DotMake.CommandLine.CliCommandAsDelegateDefinition
    {
        /// <inheritdoc />
        [DotMake.CommandLine.CliArgumentAttribute]
        public int idData { get; set; }

        /// <inheritdoc />
        public void Run()
        {
            InvokeDelegate
            (
                "1ra93x8",
                new object[]
                {
                    idData, 
                }
            );
        }

        [System.Runtime.CompilerServices.ModuleInitializerAttribute]
        internal static void Initialize()
        {
            // Register this definition class so that it can be found by the command as delegate hash.
            Register<GeneratedCode.CliCommandAsDelegate_1ra93x8>("1ra93x8");
        }
    }
}

// <auto-generated />
// Generated by DotMake.CommandLine.SourceGeneration v1.8.0.0
// Roslyn (Microsoft.CodeAnalysis) v4.800.23.57201
// Generation: 1

namespace GeneratedCode
{
    /// <inheritdoc />
    public class CliCommandAsDelegate_1ra93x8Builder : DotMake.CommandLine.CliCommandBuilder
    {
        /// <inheritdoc />
        public CliCommandAsDelegate_1ra93x8Builder()
        {
            DefinitionType = typeof(GeneratedCode.CliCommandAsDelegate_1ra93x8);
            ParentDefinitionType = null;
            NameCasingConvention = DotMake.CommandLine.CliNameCasingConvention.KebabCase;
            NamePrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.DoubleHyphen;
            ShortFormPrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.SingleHyphen;
            ShortFormAutoGenerate = true;
        }

        private GeneratedCode.CliCommandAsDelegate_1ra93x8 CreateInstance()
        {
            return new GeneratedCode.CliCommandAsDelegate_1ra93x8();
        }

        /// <inheritdoc />
        public override System.CommandLine.CliCommand Build()
        {
            // Command for 'CliCommandAsDelegate_1ra93x8' class
            var rootCommand = new System.CommandLine.CliRootCommand()
            {
            };

            var defaultClass = CreateInstance();

            // Argument for 'idData' property
            var argument0 = new System.CommandLine.CliArgument<int>
            (
                "id-data"
            )
            {
            };
            argument0.CustomParser = GetParseArgument<int>
            (
                null
            );
            argument0.DefaultValueFactory = _ => defaultClass.idData;
            rootCommand.Add(argument0);

            // Add nested or external registered children
            foreach (var child in Children)
            {
                rootCommand.Add(child.Build());
            }

            BindFunc = (parseResult) =>
            {
                var targetClass = CreateInstance();

                //  Set the parsed or default values for the options

                //  Set the parsed or default values for the arguments
                targetClass.idData = GetValueForArgument(parseResult, argument0);

                return targetClass;
            };

            rootCommand.SetAction(parseResult =>
            {
                var targetClass = (GeneratedCode.CliCommandAsDelegate_1ra93x8) BindFunc(parseResult);

                //  Call the command handler
                var cliContext = new DotMake.CommandLine.CliContext(parseResult);
                var exitCode = 0;
                targetClass.Run();
                return exitCode;
            });

            return rootCommand;
        }

        [System.Runtime.CompilerServices.ModuleInitializerAttribute]
        internal static void Initialize()
        {
            var commandBuilder = new GeneratedCode.CliCommandAsDelegate_1ra93x8Builder();

            // Register this command builder so that it can be found by the definition class
            // and it can be found by the parent definition class if it's a nested/external child.
            commandBuilder.Register();
        }
    }
}

// <auto-generated />
// Generated by DotMake.CommandLine.SourceGeneration v1.8.0.0
// Roslyn (Microsoft.CodeAnalysis) v4.800.23.57201
// Generation: 2

namespace GeneratedCode
{
    /// <inheritdoc />
    [DotMake.CommandLine.CliCommandAttribute]
    public class CliCommandAsDelegate_34pdvjr : DotMake.CommandLine.CliCommandAsDelegateDefinition
    {
        /// <inheritdoc />
        [DotMake.CommandLine.CliArgumentAttribute]
        public string PersonName { get; set; }

        /// <inheritdoc />
        [DotMake.CommandLine.CliOptionAttribute]
        public int Age { get; set; }

        /// <inheritdoc />
        public void Run()
        {
            InvokeDelegate
            (
                "34pdvjr",
                new object[]
                {
                    PersonName, 
                    Age, 
                }
            );
        }

        [System.Runtime.CompilerServices.ModuleInitializerAttribute]
        internal static void Initialize()
        {
            // Register this definition class so that it can be found by the command as delegate hash.
            Register<GeneratedCode.CliCommandAsDelegate_34pdvjr>("34pdvjr");
        }
    }
}

// <auto-generated />
// Generated by DotMake.CommandLine.SourceGeneration v1.8.0.0
// Roslyn (Microsoft.CodeAnalysis) v4.800.23.57201
// Generation: 2

namespace GeneratedCode
{
    /// <inheritdoc />
    public class CliCommandAsDelegate_34pdvjrBuilder : DotMake.CommandLine.CliCommandBuilder
    {
        /// <inheritdoc />
        public CliCommandAsDelegate_34pdvjrBuilder()
        {
            DefinitionType = typeof(GeneratedCode.CliCommandAsDelegate_34pdvjr);
            ParentDefinitionType = null;
            NameCasingConvention = DotMake.CommandLine.CliNameCasingConvention.KebabCase;
            NamePrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.DoubleHyphen;
            ShortFormPrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.SingleHyphen;
            ShortFormAutoGenerate = true;
        }

        private GeneratedCode.CliCommandAsDelegate_34pdvjr CreateInstance()
        {
            return new GeneratedCode.CliCommandAsDelegate_34pdvjr();
        }

        /// <inheritdoc />
        public override System.CommandLine.CliCommand Build()
        {
            // Command for 'CliCommandAsDelegate_34pdvjr' class
            var rootCommand = new System.CommandLine.CliRootCommand()
            {
            };

            var defaultClass = CreateInstance();

            // Option for 'Age' property
            var option0 = new System.CommandLine.CliOption<int>
            (
                "--age"
            )
            {
                Required = false,
            };
            option0.CustomParser = GetParseArgument<int>
            (
                null
            );
            option0.DefaultValueFactory = _ => defaultClass.Age;
            option0.Aliases.Add("-a");
            rootCommand.Add(option0);

            // Argument for 'PersonName' property
            var argument0 = new System.CommandLine.CliArgument<string>
            (
                "person-name"
            )
            {
            };
            argument0.CustomParser = GetParseArgument<string>
            (
                null
            );
            rootCommand.Add(argument0);

            // Add nested or external registered children
            foreach (var child in Children)
            {
                rootCommand.Add(child.Build());
            }

            BindFunc = (parseResult) =>
            {
                var targetClass = CreateInstance();

                //  Set the parsed or default values for the options
                targetClass.Age = GetValueForOption(parseResult, option0);

                //  Set the parsed or default values for the arguments
                targetClass.PersonName = GetValueForArgument(parseResult, argument0);

                return targetClass;
            };

            rootCommand.SetAction(parseResult =>
            {
                var targetClass = (GeneratedCode.CliCommandAsDelegate_34pdvjr) BindFunc(parseResult);

                //  Call the command handler
                var cliContext = new DotMake.CommandLine.CliContext(parseResult);
                var exitCode = 0;
                targetClass.Run();
                return exitCode;
            });

            return rootCommand;
        }

        [System.Runtime.CompilerServices.ModuleInitializerAttribute]
        internal static void Initialize()
        {
            var commandBuilder = new GeneratedCode.CliCommandAsDelegate_34pdvjrBuilder();

            // Register this command builder so that it can be found by the definition class
            // and it can be found by the parent definition class if it's a nested/external child.
            commandBuilder.Register();
        }
    }
}

// <auto-generated />
// Generated by DotMake.CommandLine.SourceGeneration v1.8.0.0
// Roslyn (Microsoft.CodeAnalysis) v4.800.23.57201
// Generation: 2

namespace GeneratedCode
{
    /// <inheritdoc />
    [DotMake.CommandLine.CliCommandAttribute]
    public class CliCommandAsDelegate_3r0zsnc : DotMake.CommandLine.CliCommandAsDelegateDefinition
    {
        /// <inheritdoc />
        [DotMake.CommandLine.CliArgumentAttribute]
        public string arg1 { get; set; }

        /// <inheritdoc />
        [DotMake.CommandLine.CliOptionAttribute]
        public bool opt1 { get; set; }

        /// <inheritdoc />
        public void Run()
        {
            InvokeDelegate
            (
                "3r0zsnc",
                new object[]
                {
                    arg1, 
                    opt1, 
                }
            );
        }

        [System.Runtime.CompilerServices.ModuleInitializerAttribute]
        internal static void Initialize()
        {
            // Register this definition class so that it can be found by the command as delegate hash.
            Register<GeneratedCode.CliCommandAsDelegate_3r0zsnc>("3r0zsnc");
        }
    }
}

// <auto-generated />
// Generated by DotMake.CommandLine.SourceGeneration v1.8.0.0
// Roslyn (Microsoft.CodeAnalysis) v4.800.23.57201
// Generation: 2

namespace GeneratedCode
{
    /// <inheritdoc />
    public class CliCommandAsDelegate_3r0zsncBuilder : DotMake.CommandLine.CliCommandBuilder
    {
        /// <inheritdoc />
        public CliCommandAsDelegate_3r0zsncBuilder()
        {
            DefinitionType = typeof(GeneratedCode.CliCommandAsDelegate_3r0zsnc);
            ParentDefinitionType = null;
            NameCasingConvention = DotMake.CommandLine.CliNameCasingConvention.KebabCase;
            NamePrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.DoubleHyphen;
            ShortFormPrefixConvention = DotMake.CommandLine.CliNamePrefixConvention.SingleHyphen;
            ShortFormAutoGenerate = true;
        }

        private GeneratedCode.CliCommandAsDelegate_3r0zsnc CreateInstance()
        {
            return new GeneratedCode.CliCommandAsDelegate_3r0zsnc();
        }

        /// <inheritdoc />
        public override System.CommandLine.CliCommand Build()
        {
            // Command for 'CliCommandAsDelegate_3r0zsnc' class
            var rootCommand = new System.CommandLine.CliRootCommand()
            {
            };

            var defaultClass = CreateInstance();

            // Option for 'opt1' property
            var option0 = new System.CommandLine.CliOption<bool>
            (
                "--opt-1"
            )
            {
                Required = false,
            };
            option0.CustomParser = GetParseArgument<bool>
            (
                null
            );
            option0.DefaultValueFactory = _ => defaultClass.opt1;
            option0.Aliases.Add("-o");
            rootCommand.Add(option0);

            // Argument for 'arg1' property
            var argument0 = new System.CommandLine.CliArgument<string>
            (
                "arg-1"
            )
            {
            };
            argument0.CustomParser = GetParseArgument<string>
            (
                null
            );
            rootCommand.Add(argument0);

            // Add nested or external registered children
            foreach (var child in Children)
            {
                rootCommand.Add(child.Build());
            }

            BindFunc = (parseResult) =>
            {
                var targetClass = CreateInstance();

                //  Set the parsed or default values for the options
                targetClass.opt1 = GetValueForOption(parseResult, option0);

                //  Set the parsed or default values for the arguments
                targetClass.arg1 = GetValueForArgument(parseResult, argument0);

                return targetClass;
            };

            rootCommand.SetAction(parseResult =>
            {
                var targetClass = (GeneratedCode.CliCommandAsDelegate_3r0zsnc) BindFunc(parseResult);

                //  Call the command handler
                var cliContext = new DotMake.CommandLine.CliContext(parseResult);
                var exitCode = 0;
                targetClass.Run();
                return exitCode;
            });

            return rootCommand;
        }

        [System.Runtime.CompilerServices.ModuleInitializerAttribute]
        internal static void Initialize()
        {
            var commandBuilder = new GeneratedCode.CliCommandAsDelegate_3r0zsncBuilder();

            // Register this command builder so that it can be found by the definition class
            // and it can be found by the parent definition class if it's a nested/external child.
            commandBuilder.Register();
        }
    }
}

Code and pdf at

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

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.