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