diff --git a/README.md b/README.md index 9404369b2..15a466961 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,7 @@ dotnet run - [Default values](readme/default-values.md) - [Required properties or fields](readme/required-properties-or-fields.md) - [Root binding](readme/root-binding.md) +- [Async Root](readme/async-root.md) ### Lifetimes - [Transient](readme/transient.md) - [Singleton](readme/singleton.md) @@ -244,6 +245,7 @@ dotnet run - [Generic composition roots](readme/generic-composition-roots.md) - [Complex generics](readme/complex-generics.md) - [Generic composition roots with constraints](readme/generic-composition-roots-with-constraints.md) +- [Generic async composition roots with constraints](readme/generic-async-composition-roots-with-constraints.md) ### Attributes - [Constructor ordinal attribute](readme/constructor-ordinal-attribute.md) - [Member ordinal attribute](readme/member-ordinal-attribute.md) diff --git a/readme/async-disposable-scope.md b/readme/async-disposable-scope.md index c8a89278a..af3de14d8 100644 --- a/readme/async-disposable-scope.md +++ b/readme/async-disposable-scope.md @@ -146,8 +146,8 @@ partial class Composition: IDisposable, IAsyncDisposable () => { Composition transientComposition2 = this; - var localValue29 = new Session(transientComposition2); - return localValue29; + var localValue51 = new Session(transientComposition2); + return localValue51; }); } } diff --git a/readme/async-root.md b/readme/async-root.md new file mode 100644 index 000000000..da868e58b --- /dev/null +++ b/readme/async-root.md @@ -0,0 +1,138 @@ +#### Async Root + +[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/AsyncRootScenario.cs) + + +```c# +interface IDependency; + +class Dependency : IDependency; + +interface IService; + +class Service(IDependency dependency) : IService; + +DI.Setup(nameof(Composition)) + .Bind().To() + .Bind().To() + + // Composition root + .Root>("GetMyServiceAsync", kind: RootKinds.Method); + +var composition = new Composition(); +using var cancellationTokenSource = new CancellationTokenSource(); + +// Creates the composition root asynchronously +var service = await composition.GetMyServiceAsync(); +``` + +The following partial class will be generated: + +```c# +partial class Composition +{ + private readonly Composition _root; + private readonly object _lock; + + public Composition() + { + _root = this; + _lock = new object(); + } + + internal Composition(Composition parentScope) + { + _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; + _lock = _root._lock; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Task GetMyServiceAsync() + { + var perResolveFunc40 = default(Func); + TaskScheduler transientTaskScheduler5 = TaskScheduler.Default; + TaskContinuationOptions transientTaskContinuationOptions4 = TaskContinuationOptions.None; + TaskCreationOptions transientTaskCreationOptions3 = TaskCreationOptions.None; + CancellationToken transientCancellationToken2 = CancellationToken.None; + TaskFactory perBlockTaskFactory1; + { + var localCancellationToken10 = transientCancellationToken2; + var localTaskCreationOptions11 = transientTaskCreationOptions3; + var localTaskContinuationOptions12 = transientTaskContinuationOptions4; + var localTaskScheduler13 = transientTaskScheduler5; + perBlockTaskFactory1 = new TaskFactory(localCancellationToken10, localTaskCreationOptions11, localTaskContinuationOptions12, localTaskScheduler13); + } + + if (perResolveFunc40 == null) + { + lock (_lock) + { + if (perResolveFunc40 == null) + { + perResolveFunc40 = new Func( + [MethodImpl(MethodImplOptions.AggressiveInlining)] + () => + { + var localValue14 = new Service(new Dependency()); + return localValue14; + }); + } + } + } + + Task transientTask0; + { + var localFactory15 = perResolveFunc40!; + var localTaskFactory16 = perBlockTaskFactory1; + transientTask0 = localTaskFactory16.StartNew(localFactory15); + } + + return transientTask0; + } +} +``` + +Class diagram: + +```mermaid +classDiagram + class Composition { + <> + +TaskᐸIServiceᐳ GetMyServiceAsync() + } + class CancellationToken + class TaskScheduler + class TaskCreationOptions + class TaskContinuationOptions + class TaskFactory + Dependency --|> IDependency + class Dependency { + +Dependency() + } + Service --|> IService + class Service { + +Service(IDependency dependency) + } + class FuncᐸIServiceᐳ + class TaskFactoryᐸIServiceᐳ + class IDependency { + <> + } + class IService { + <> + } + TaskFactory *-- CancellationToken : CancellationToken + TaskFactory *-- TaskCreationOptions : TaskCreationOptions + TaskFactory *-- TaskContinuationOptions : TaskContinuationOptions + TaskFactory *-- TaskScheduler : TaskScheduler + Service *-- Dependency : IDependency + Composition ..> TaskᐸIServiceᐳ : TaskᐸIServiceᐳ GetMyServiceAsync() + TaskᐸIServiceᐳ o-- "PerResolve" FuncᐸIServiceᐳ : FuncᐸIServiceᐳ + TaskᐸIServiceᐳ o-- "PerBlock" TaskFactoryᐸIServiceᐳ : TaskFactoryᐸIServiceᐳ + FuncᐸIServiceᐳ *-- Service : IService + TaskFactoryᐸIServiceᐳ *-- CancellationToken : CancellationToken + TaskFactoryᐸIServiceᐳ *-- TaskCreationOptions : TaskCreationOptions + TaskFactoryᐸIServiceᐳ *-- TaskContinuationOptions : TaskContinuationOptions + TaskFactoryᐸIServiceᐳ *-- TaskScheduler : TaskScheduler +``` + diff --git a/readme/auto-scoped.md b/readme/auto-scoped.md index 7e2056de2..1bcb853a2 100644 --- a/readme/auto-scoped.md +++ b/readme/auto-scoped.md @@ -125,14 +125,14 @@ partial class Composition Composition transientComposition2 = this; IService transientIService1; { - var localBaseComposition31 = transientComposition2; + var localBaseComposition53 = transientComposition2; // Creates a session - var localSession32 = new Composition(localBaseComposition31); - transientIService1 = localSession32.SessionRoot; + var localSession54 = new Composition(localBaseComposition53); + transientIService1 = localSession54.SessionRoot; } - var localValue30 = transientIService1; - return localValue30; + var localValue52 = transientIService1; + return localValue52; }); } } diff --git a/readme/factory.md b/readme/factory.md index 05fccab4d..39f971cef 100644 --- a/readme/factory.md +++ b/readme/factory.md @@ -85,9 +85,9 @@ partial class Composition DateTimeOffset transientDateTimeOffset3 = DateTimeOffset.Now; Dependency transientDependency1; { - var localDependency10 = new Dependency(transientDateTimeOffset3); - localDependency10.Initialize(); - transientDependency1 = localDependency10; + var localDependency17 = new Dependency(transientDateTimeOffset3); + localDependency17.Initialize(); + transientDependency1 = localDependency17; } return new Service(transientDependency1); diff --git a/readme/func-with-arguments.md b/readme/func-with-arguments.md index 1bc449e3e..ee4b8bcb3 100644 --- a/readme/func-with-arguments.md +++ b/readme/func-with-arguments.md @@ -107,8 +107,8 @@ partial class Composition } } - var localDependency12 = new Dependency(_root._singletonClock36!, transientInt323); - return localDependency12; + var localDependency19 = new Dependency(_root._singletonClock36!, transientInt323); + return localDependency19; }; return new Service(transientFunc1); } diff --git a/readme/func-with-tag.md b/readme/func-with-tag.md index cae194097..fc5187bdd 100644 --- a/readme/func-with-tag.md +++ b/readme/func-with-tag.md @@ -72,8 +72,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - var localValue13 = new Dependency(); - return localValue13; + var localValue20 = new Dependency(); + return localValue20; }); } } diff --git a/readme/func.md b/readme/func.md index 33eea386b..207d10775 100644 --- a/readme/func.md +++ b/readme/func.md @@ -75,8 +75,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - var localValue11 = new Dependency(); - return localValue11; + var localValue18 = new Dependency(); + return localValue18; }); } } diff --git a/readme/generic-async-composition-roots-with-constraints.md b/readme/generic-async-composition-roots-with-constraints.md new file mode 100644 index 000000000..b545b6f62 --- /dev/null +++ b/readme/generic-async-composition-roots-with-constraints.md @@ -0,0 +1,237 @@ +#### Generic async composition roots with constraints + +[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Generics/GenericAsyncCompositionRootsWithConstraintsScenario.cs) + + +```c# +interface IDependency + where T: IDisposable; + +class Dependency : IDependency + where T: IDisposable; + +interface IService + where T: IDisposable + where TStruct: struct; + +class Service(IDependency dependency) : IService + where T: IDisposable + where TStruct: struct; + +class OtherService(IDependency dependency) : IService + where T: IDisposable; + +DI.Setup(nameof(Composition)) + // This hint indicates to not generate methods such as Resolve + .Hint(Hint.Resolve, "Off") + .Bind().To>() + .Bind().To>() + // Creates OtherService manually, + // just for the sake of example + .Bind("Other").To(ctx => + { + ctx.Inject(out IDependency dependency); + return new OtherService(dependency); + }) + + // Specifies to create a regular public method + // to get a composition root of type Task> + // with the name "GetMyRootAsync" + .Root>>("GetMyRootAsync") + + // Specifies to create a regular public method + // to get a composition root of type Task> + // with the name "GetOtherServiceAsync" + // using the "Other" tag + .Root>>("GetOtherServiceAsync", "Other"); + +var composition = new Composition(); + +// Creates composition roots asynchronously +var service = await composition.GetMyRootAsync(); +var someOtherService = await composition.GetOtherServiceAsync(); +``` + +> [!IMPORTANT] +> `Resolve' methods cannot be used to resolve generic composition roots. + +The following partial class will be generated: + +```c# +partial class Composition +{ + private readonly Composition _root; + private readonly object _lock; + + public Composition() + { + _root = this; + _lock = new object(); + } + + internal Composition(Composition parentScope) + { + _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; + _lock = _root._lock; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Task> GetMyRootAsync() + where T: IDisposable + where T1: struct + { + var perResolveFunc42 = default(Func>); + TaskScheduler transientTaskScheduler5 = TaskScheduler.Default; + TaskContinuationOptions transientTaskContinuationOptions4 = TaskContinuationOptions.None; + TaskCreationOptions transientTaskCreationOptions3 = TaskCreationOptions.None; + CancellationToken transientCancellationToken2 = CancellationToken.None; + TaskFactory> perBlockTaskFactory1; + { + var localCancellationToken34 = transientCancellationToken2; + var localTaskCreationOptions35 = transientTaskCreationOptions3; + var localTaskContinuationOptions36 = transientTaskContinuationOptions4; + var localTaskScheduler37 = transientTaskScheduler5; + perBlockTaskFactory1 = new TaskFactory>(localCancellationToken34, localTaskCreationOptions35, localTaskContinuationOptions36, localTaskScheduler37); + } + + if (perResolveFunc42 == null) + { + lock (_lock) + { + if (perResolveFunc42 == null) + { + perResolveFunc42 = new Func>( + [MethodImpl(MethodImplOptions.AggressiveInlining)] + () => + { + var localValue38 = new Service(new Dependency()); + return localValue38; + }); + } + } + } + + Task> transientTask0; + { + var localFactory39 = perResolveFunc42!; + var localTaskFactory40 = perBlockTaskFactory1; + transientTask0 = localTaskFactory40.StartNew(localFactory39); + } + + return transientTask0; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Task> GetOtherServiceAsync() + where T: IDisposable + { + var perResolveFunc44 = default(Func>); + TaskScheduler transientTaskScheduler5 = TaskScheduler.Default; + TaskContinuationOptions transientTaskContinuationOptions4 = TaskContinuationOptions.None; + TaskCreationOptions transientTaskCreationOptions3 = TaskCreationOptions.None; + CancellationToken transientCancellationToken2 = CancellationToken.None; + TaskFactory> perBlockTaskFactory1; + { + var localCancellationToken41 = transientCancellationToken2; + var localTaskCreationOptions42 = transientTaskCreationOptions3; + var localTaskContinuationOptions43 = transientTaskContinuationOptions4; + var localTaskScheduler44 = transientTaskScheduler5; + perBlockTaskFactory1 = new TaskFactory>(localCancellationToken41, localTaskCreationOptions42, localTaskContinuationOptions43, localTaskScheduler44); + } + + if (perResolveFunc44 == null) + { + lock (_lock) + { + if (perResolveFunc44 == null) + { + perResolveFunc44 = new Func>( + [MethodImpl(MethodImplOptions.AggressiveInlining)] + () => + { + OtherService transientOtherService6; + { + var localDependency46 = new Dependency(); + transientOtherService6 = new OtherService(localDependency46); + } + + var localValue45 = transientOtherService6; + return localValue45; + }); + } + } + } + + Task> transientTask0; + { + var localFactory47 = perResolveFunc44!; + var localTaskFactory48 = perBlockTaskFactory1; + transientTask0 = localTaskFactory48.StartNew(localFactory47); + } + + return transientTask0; + } +} +``` + +Class diagram: + +```mermaid +classDiagram + class Composition { + <> + +TaskᐸIServiceᐸTˏT1ᐳᐳ GetMyRootAsyncᐸTˏT1ᐳ() + +TaskᐸIServiceᐸTˏBooleanᐳᐳ GetOtherServiceAsyncᐸTᐳ() + } + class CancellationToken + class TaskScheduler + class TaskCreationOptions + class TaskContinuationOptions + class TaskFactory + class FuncᐸIServiceᐸTˏT1ᐳᐳ + class TaskFactoryᐸIServiceᐸTˏT1ᐳᐳ + class FuncᐸIServiceᐸTˏBooleanᐳᐳ + class TaskFactoryᐸIServiceᐸTˏBooleanᐳᐳ + ServiceᐸTˏT1ᐳ --|> IServiceᐸTˏT1ᐳ + class ServiceᐸTˏT1ᐳ { + +Service(IDependencyᐸTᐳ dependency) + } + OtherServiceᐸTᐳ --|> IServiceᐸTˏBooleanᐳ : "Other" + class OtherServiceᐸTᐳ + DependencyᐸTᐳ --|> IDependencyᐸTᐳ + class DependencyᐸTᐳ { + +Dependency() + } + class IServiceᐸTˏT1ᐳ { + <> + } + class IServiceᐸTˏBooleanᐳ { + <> + } + class IDependencyᐸTᐳ { + <> + } + TaskFactory *-- CancellationToken : CancellationToken + TaskFactory *-- TaskCreationOptions : TaskCreationOptions + TaskFactory *-- TaskContinuationOptions : TaskContinuationOptions + TaskFactory *-- TaskScheduler : TaskScheduler + Composition ..> TaskᐸIServiceᐸTˏT1ᐳᐳ : TaskᐸIServiceᐸTˏT1ᐳᐳ GetMyRootAsyncᐸTˏT1ᐳ() + Composition ..> TaskᐸIServiceᐸTˏBooleanᐳᐳ : TaskᐸIServiceᐸTˏBooleanᐳᐳ GetOtherServiceAsyncᐸTᐳ() + TaskᐸIServiceᐸTˏT1ᐳᐳ o-- "PerResolve" FuncᐸIServiceᐸTˏT1ᐳᐳ : FuncᐸIServiceᐸTˏT1ᐳᐳ + TaskᐸIServiceᐸTˏT1ᐳᐳ o-- "PerBlock" TaskFactoryᐸIServiceᐸTˏT1ᐳᐳ : TaskFactoryᐸIServiceᐸTˏT1ᐳᐳ + TaskᐸIServiceᐸTˏBooleanᐳᐳ o-- "PerResolve" FuncᐸIServiceᐸTˏBooleanᐳᐳ : "Other" FuncᐸIServiceᐸTˏBooleanᐳᐳ + TaskᐸIServiceᐸTˏBooleanᐳᐳ o-- "PerBlock" TaskFactoryᐸIServiceᐸTˏBooleanᐳᐳ : TaskFactoryᐸIServiceᐸTˏBooleanᐳᐳ + FuncᐸIServiceᐸTˏT1ᐳᐳ *-- ServiceᐸTˏT1ᐳ : IServiceᐸTˏT1ᐳ + TaskFactoryᐸIServiceᐸTˏT1ᐳᐳ *-- CancellationToken : CancellationToken + TaskFactoryᐸIServiceᐸTˏT1ᐳᐳ *-- TaskCreationOptions : TaskCreationOptions + TaskFactoryᐸIServiceᐸTˏT1ᐳᐳ *-- TaskContinuationOptions : TaskContinuationOptions + TaskFactoryᐸIServiceᐸTˏT1ᐳᐳ *-- TaskScheduler : TaskScheduler + FuncᐸIServiceᐸTˏBooleanᐳᐳ *-- OtherServiceᐸTᐳ : "Other" IServiceᐸTˏBooleanᐳ + TaskFactoryᐸIServiceᐸTˏBooleanᐳᐳ *-- CancellationToken : CancellationToken + TaskFactoryᐸIServiceᐸTˏBooleanᐳᐳ *-- TaskCreationOptions : TaskCreationOptions + TaskFactoryᐸIServiceᐸTˏBooleanᐳᐳ *-- TaskContinuationOptions : TaskContinuationOptions + TaskFactoryᐸIServiceᐸTˏBooleanᐳᐳ *-- TaskScheduler : TaskScheduler + ServiceᐸTˏT1ᐳ *-- DependencyᐸTᐳ : IDependencyᐸTᐳ + OtherServiceᐸTᐳ *-- DependencyᐸTᐳ : IDependencyᐸTᐳ +``` + diff --git a/readme/generic-composition-roots-with-constraints.md b/readme/generic-composition-roots-with-constraints.md index c9813cb19..473e6e73a 100644 --- a/readme/generic-composition-roots-with-constraints.md +++ b/readme/generic-composition-roots-with-constraints.md @@ -88,8 +88,8 @@ partial class Composition { OtherService transientOtherService0; { - var localDependency27 = new Dependency(); - transientOtherService0 = new OtherService(localDependency27); + var localDependency49 = new Dependency(); + transientOtherService0 = new OtherService(localDependency49); } return transientOtherService0; diff --git a/readme/generic-composition-roots.md b/readme/generic-composition-roots.md index 897f732a3..09e5e5405 100644 --- a/readme/generic-composition-roots.md +++ b/readme/generic-composition-roots.md @@ -80,8 +80,8 @@ partial class Composition { OtherService transientOtherService0; { - var localDependency28 = new Dependency(); - transientOtherService0 = new OtherService(localDependency28); + var localDependency50 = new Dependency(); + transientOtherService0 = new OtherService(localDependency50); } return transientOtherService0; diff --git a/readme/lazy.md b/readme/lazy.md index 5fe7194dc..0296f1370 100644 --- a/readme/lazy.md +++ b/readme/lazy.md @@ -66,8 +66,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - var localValue14 = new Dependency(); - return localValue14; + var localValue21 = new Dependency(); + return localValue21; }); } } @@ -75,8 +75,8 @@ partial class Composition Lazy transientLazy1; { - var localFactory15 = perResolveFunc40!; - transientLazy1 = new Lazy(localFactory15, true); + var localFactory22 = perResolveFunc40!; + transientLazy1 = new Lazy(localFactory22, true); } return new Service(transientLazy1); diff --git a/readme/manually-started-tasks.md b/readme/manually-started-tasks.md index 29ab8e812..cff9d808a 100644 --- a/readme/manually-started-tasks.md +++ b/readme/manually-started-tasks.md @@ -101,8 +101,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - var localValue16 = new Dependency(); - return localValue16; + var localValue23 = new Dependency(); + return localValue23; }); } } @@ -110,9 +110,9 @@ partial class Composition Task transientTask1; { - var localFactory17 = perResolveFunc42!; - var localCancellationToken18 = cancellationToken; - transientTask1 = new Task(localFactory17, localCancellationToken18); + var localFactory24 = perResolveFunc42!; + var localCancellationToken25 = cancellationToken; + transientTask1 = new Task(localFactory24, localCancellationToken25); } return new Service(transientTask1); diff --git a/readme/scope.md b/readme/scope.md index a17549a95..a03ffc2e2 100644 --- a/readme/scope.md +++ b/readme/scope.md @@ -144,8 +144,8 @@ partial class Composition: IDisposable () => { Composition transientComposition2 = this; - var localValue33 = new Session(transientComposition2); - return localValue33; + var localValue55 = new Session(transientComposition2); + return localValue55; }); } } diff --git a/readme/task.md b/readme/task.md index 129effec7..b9ecda475 100644 --- a/readme/task.md +++ b/readme/task.md @@ -87,11 +87,11 @@ partial class Composition TaskCreationOptions transientTaskCreationOptions3 = TaskCreationOptions.None; TaskFactory perBlockTaskFactory2; { - var localCancellationToken19 = cancellationToken; - var localTaskCreationOptions20 = transientTaskCreationOptions3; - var localTaskContinuationOptions21 = transientTaskContinuationOptions4; - var localTaskScheduler22 = transientTaskScheduler5; - perBlockTaskFactory2 = new TaskFactory(localCancellationToken19, localTaskCreationOptions20, localTaskContinuationOptions21, localTaskScheduler22); + var localCancellationToken26 = cancellationToken; + var localTaskCreationOptions27 = transientTaskCreationOptions3; + var localTaskContinuationOptions28 = transientTaskContinuationOptions4; + var localTaskScheduler29 = transientTaskScheduler5; + perBlockTaskFactory2 = new TaskFactory(localCancellationToken26, localTaskCreationOptions27, localTaskContinuationOptions28, localTaskScheduler29); } if (perResolveFunc42 == null) @@ -104,8 +104,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - var localValue23 = new Dependency(); - return localValue23; + var localValue30 = new Dependency(); + return localValue30; }); } } @@ -113,9 +113,9 @@ partial class Composition Task transientTask1; { - var localFactory24 = perResolveFunc42!; - var localTaskFactory25 = perBlockTaskFactory2; - transientTask1 = localTaskFactory25.StartNew(localFactory24); + var localFactory31 = perResolveFunc42!; + var localTaskFactory32 = perBlockTaskFactory2; + transientTask1 = localTaskFactory32.StartNew(localFactory31); } return new Service(transientTask1); diff --git a/readme/valuetask.md b/readme/valuetask.md index 5350d62db..9bce482ef 100644 --- a/readme/valuetask.md +++ b/readme/valuetask.md @@ -64,8 +64,8 @@ partial class Composition { ValueTask transientValueTask1; { - var localValue26 = new Dependency(); - transientValueTask1 = new ValueTask(localValue26); + var localValue33 = new Dependency(); + transientValueTask1 = new ValueTask(localValue33); } return new Service(transientValueTask1); diff --git a/tests/Pure.DI.UsageTests/Basics/AsyncRootScenario.cs b/tests/Pure.DI.UsageTests/Basics/AsyncRootScenario.cs new file mode 100644 index 000000000..57f1d3eef --- /dev/null +++ b/tests/Pure.DI.UsageTests/Basics/AsyncRootScenario.cs @@ -0,0 +1,47 @@ +/* +$v=true +$p=18 +$d=Async Root +*/ + +// ReSharper disable ArrangeTypeModifiers +// ReSharper disable CheckNamespace +#pragma warning disable CS9113 // Parameter is unread. +namespace Pure.DI.UsageTests.Basics.AsyncRootScenario; + +using Xunit; + +// { +interface IDependency; + +class Dependency : IDependency; + +interface IService; + +class Service(IDependency dependency) : IService; +// } + +public class Scenario +{ + [Fact] + public async Task Run() + { + // Resolve = Off +// { + DI.Setup(nameof(Composition)) + .Bind().To() + .Bind().To() + + // Composition root + .Root>("GetMyServiceAsync", kind: RootKinds.Method); + + var composition = new Composition(); + using var cancellationTokenSource = new CancellationTokenSource(); + + // Creates the composition root asynchronously + var service = await composition.GetMyServiceAsync(); +// } + service.ShouldBeOfType(); + composition.SaveClassDiagram(); + } +} \ No newline at end of file diff --git a/tests/Pure.DI.UsageTests/Generics/GenericAsyncCompositionRootsWithConstraintsScenario.cs b/tests/Pure.DI.UsageTests/Generics/GenericAsyncCompositionRootsWithConstraintsScenario.cs new file mode 100644 index 000000000..9aa38a84e --- /dev/null +++ b/tests/Pure.DI.UsageTests/Generics/GenericAsyncCompositionRootsWithConstraintsScenario.cs @@ -0,0 +1,81 @@ +/* +$v=true +$p=5 +$d=Generic async composition roots with constraints +$f=> [!IMPORTANT] +$f=> `Resolve' methods cannot be used to resolve generic composition roots. +*/ + +// ReSharper disable ClassNeverInstantiated.Local +// ReSharper disable CheckNamespace +// ReSharper disable UnusedParameter.Local +// ReSharper disable ArrangeTypeModifiers +// ReSharper disable ClassNeverInstantiated.Global +// ReSharper disable UnusedVariable +// ReSharper disable UnusedTypeParameter +#pragma warning disable CS9113 // Parameter is unread. +namespace Pure.DI.UsageTests.Generics.GenericAsyncCompositionRootsWithConstraintsScenario; + +using Shouldly; +using Xunit; + +// { +interface IDependency + where T: IDisposable; + +class Dependency : IDependency + where T: IDisposable; + +interface IService + where T: IDisposable + where TStruct: struct; + +class Service(IDependency dependency) : IService + where T: IDisposable + where TStruct: struct; + +class OtherService(IDependency dependency) : IService + where T: IDisposable; +// } + +public class Scenario +{ + [Fact] + public async Task Run() + { +// { + DI.Setup(nameof(Composition)) + // This hint indicates to not generate methods such as Resolve + .Hint(Hint.Resolve, "Off") + .Bind().To>() + .Bind().To>() + // Creates OtherService manually, + // just for the sake of example + .Bind("Other").To(ctx => + { + ctx.Inject(out IDependency dependency); + return new OtherService(dependency); + }) + + // Specifies to create a regular public method + // to get a composition root of type Task> + // with the name "GetMyRootAsync" + .Root>>("GetMyRootAsync") + + // Specifies to create a regular public method + // to get a composition root of type Task> + // with the name "GetOtherServiceAsync" + // using the "Other" tag + .Root>>("GetOtherServiceAsync", "Other"); + + var composition = new Composition(); + + // Creates composition roots asynchronously + var service = await composition.GetMyRootAsync(); + var someOtherService = await composition.GetOtherServiceAsync(); +// } + service.ShouldBeOfType>(); + someOtherService.ShouldBeOfType>(); + composition.SaveClassDiagram(); + } +} \ No newline at end of file