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
Leave a Reply