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