From 98f41b5c37ee65b07ec79960ee7ece8414e511a9 Mon Sep 17 00:00:00 2001 From: Nikolay Pianikov Date: Tue, 30 Jul 2024 12:18:57 +0300 Subject: [PATCH] Bind attr --- README.md | 2 + readme/async-disposable-scope.md | 4 +- readme/async-root.md | 20 +- readme/auto-scoped.md | 10 +- readme/exposed-generic-roots.md | 3 + readme/exposed-roots-via-arg.md | 200 ++++++++++++++++++ readme/exposed-roots-via-root-arg.md | 80 +++++++ readme/exposed-roots-with-tags.md | 4 +- readme/exposed-roots.md | 3 + readme/factory.md | 6 +- readme/func-with-arguments.md | 4 +- readme/func-with-tag.md | 4 +- readme/func.md | 4 +- ...sync-composition-roots-with-constraints.md | 44 ++-- ...eric-composition-roots-with-constraints.md | 4 +- readme/generic-composition-roots.md | 4 +- readme/lazy.md | 8 +- readme/manually-started-tasks.md | 10 +- readme/scope.md | 4 +- readme/task.md | 20 +- ...async-disposable-instances-in-delegates.md | 10 +- ...osable-instances-per-a-composition-root.md | 6 +- ...cking-disposable-instances-in-delegates.md | 10 +- ...osable-instances-per-a-composition-root.md | 6 +- readme/valuetask.md | 4 +- .../Advanced/ExposedGenericRootsScenario.cs | 2 + .../Advanced/ExposedRootsScenario.cs | 2 + .../Advanced/ExposedRootsViaArgScenario.cs | 66 ++++++ .../ExposedRootsViaRootArgScenario.cs | 67 ++++++ 29 files changed, 518 insertions(+), 93 deletions(-) create mode 100644 readme/exposed-roots-via-arg.md create mode 100644 readme/exposed-roots-via-root-arg.md create mode 100644 tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaArgScenario.cs create mode 100644 tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaRootArgScenario.cs diff --git a/README.md b/README.md index b89960b1e..c96b5a864 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,8 @@ dotnet run - [Tracking async disposable instances in delegates](readme/tracking-async-disposable-instances-in-delegates.md) - [Exposed roots](readme/exposed-roots.md) - [Exposed roots with tags](readme/exposed-roots-with-tags.md) +- [Exposed roots via arg](readme/exposed-roots-via-arg.md) +- [Exposed roots via root arg](readme/exposed-roots-via-root-arg.md) - [Exposed generic roots](readme/exposed-generic-roots.md) - [Exposed generic roots it args](readme/exposed-generic-roots-it-args.md) ### Applications diff --git a/readme/async-disposable-scope.md b/readme/async-disposable-scope.md index 7a46ff57f..ec6f8df45 100644 --- a/readme/async-disposable-scope.md +++ b/readme/async-disposable-scope.md @@ -148,8 +148,8 @@ partial class Composition: IDisposable, IAsyncDisposable () => { Composition transientComposition2 = this; - Session localValue56 = new Session(transientComposition2); - return localValue56; + Session localValue58 = new Session(transientComposition2); + return localValue58; }); } } diff --git a/readme/async-root.md b/readme/async-root.md index 8cb9974fb..b110735b1 100644 --- a/readme/async-root.md +++ b/readme/async-root.md @@ -59,11 +59,11 @@ partial class Composition TaskCreationOptions transientTaskCreationOptions2 = TaskCreationOptions.None; TaskFactory perBlockTaskFactory1; { - CancellationToken localCancellationToken15 = cancellationToken; - TaskCreationOptions localTaskCreationOptions16 = transientTaskCreationOptions2; - TaskContinuationOptions localTaskContinuationOptions17 = transientTaskContinuationOptions3; - TaskScheduler localTaskScheduler18 = transientTaskScheduler4; - perBlockTaskFactory1 = new TaskFactory(localCancellationToken15, localTaskCreationOptions16, localTaskContinuationOptions17, localTaskScheduler18); + CancellationToken localCancellationToken17 = cancellationToken; + TaskCreationOptions localTaskCreationOptions18 = transientTaskCreationOptions2; + TaskContinuationOptions localTaskContinuationOptions19 = transientTaskContinuationOptions3; + TaskScheduler localTaskScheduler20 = transientTaskScheduler4; + perBlockTaskFactory1 = new TaskFactory(localCancellationToken17, localTaskCreationOptions18, localTaskContinuationOptions19, localTaskScheduler20); } if (perResolveFunc45 == null) @@ -76,8 +76,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - IService localValue19 = new Service(new Dependency()); - return localValue19; + IService localValue21 = new Service(new Dependency()); + return localValue21; }); } } @@ -85,9 +85,9 @@ partial class Composition Task transientTask0; { - Func localFactory20 = perResolveFunc45!; - TaskFactory localTaskFactory21 = perBlockTaskFactory1; - transientTask0 = localTaskFactory21.StartNew(localFactory20); + Func localFactory22 = perResolveFunc45!; + TaskFactory localTaskFactory23 = perBlockTaskFactory1; + transientTask0 = localTaskFactory23.StartNew(localFactory22); } return transientTask0; diff --git a/readme/auto-scoped.md b/readme/auto-scoped.md index 8f68d37bf..977a93fa1 100644 --- a/readme/auto-scoped.md +++ b/readme/auto-scoped.md @@ -109,14 +109,14 @@ partial class Composition Composition transientComposition2 = this; IService transientIService1; { - Composition localBaseComposition58 = transientComposition2; + Composition localBaseComposition60 = transientComposition2; // Creates a session - var localSession59 = new Composition(localBaseComposition58); - transientIService1 = localSession59.SessionRoot; + var localSession61 = new Composition(localBaseComposition60); + transientIService1 = localSession61.SessionRoot; } - IService localValue57 = transientIService1; - return localValue57; + IService localValue59 = transientIService1; + return localValue59; }); } } diff --git a/readme/exposed-generic-roots.md b/readme/exposed-generic-roots.md index 76ec36430..05e4342e3 100644 --- a/readme/exposed-generic-roots.md +++ b/readme/exposed-generic-roots.md @@ -45,6 +45,9 @@ var program = composition.Program; program.DoSomething(99); ``` +> [!IMPORTANT] +> At this point, a composition from another assembly or another project can be used for this purpose. Compositions from the current project cannot be used in this way due to limitations of the source code generators. + The following partial class will be generated: ```c# diff --git a/readme/exposed-roots-via-arg.md b/readme/exposed-roots-via-arg.md new file mode 100644 index 000000000..deb681bac --- /dev/null +++ b/readme/exposed-roots-via-arg.md @@ -0,0 +1,200 @@ +#### Exposed roots via arg + +[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaArgScenario.cs) + +Composition roots from other assemblies or projects can be used as a source of bindings passed through class arguments. When you add a binding to a composition from another assembly or project, the roots of the composition with the `RootKind.Exposed` type will be used in the bindings automatically. For example, in some assembly a composition is defined as: +```c# +public partial class CompositionInOtherProject +{ + private static void Setup() => + DI.Setup() + .Bind().As(Lifetime.Singleton).To() + .Bind().To() + .Root("MyService", kind: RootKinds.Exposed); +} +``` + + +```c# +interface IDependency; + +class Dependency : IDependency; + +interface IService; + +class Service(IDependency dependency) : IService; + +class Program(IService service, IMyService myService) +{ + public IService Service { get; } = service; + + public void DoSomething() => myService.DoSomething(); +} + +DI.Setup(nameof(Composition)) + .Bind().To() + .Bind().To() + // Binds to exposed composition roots from other project + .Arg("baseComposition") + .Root("Program"); + +var baseComposition = new CompositionInOtherProject(); +var composition = new Composition(baseComposition); +var program = composition.Program; +program.DoSomething(); +``` + +The following partial class will be generated: + +```c# +partial class Composition +{ + private readonly Composition _root; + + private readonly Integration.CompositionInOtherProject _argBaseComposition; + + [OrdinalAttribute(10)] + public Composition(Integration.CompositionInOtherProject baseComposition) + { + _argBaseComposition = baseComposition ?? throw new ArgumentNullException(nameof(baseComposition)); + _root = this; + } + + internal Composition(Composition parentScope) + { + _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; + _argBaseComposition = _root._argBaseComposition; + } + + public Program Program + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + Integration.IMyService transientIMyService2; + { + Integration.CompositionInOtherProject localValue4 = _argBaseComposition; + transientIMyService2 = localValue4.MyService; + } + + return new Program(new Service(new Dependency()), transientIMyService2); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Resolve() + { + return Resolver.Value.Resolve(this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Resolve(object? tag) + { + return Resolver.Value.ResolveByTag(this, tag); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public object Resolve(Type type) + { + var index = (int)(_bucketSize * ((uint)RuntimeHelpers.GetHashCode(type) % 1)); + ref var pair = ref _buckets[index]; + return pair.Key == type ? pair.Value.Resolve(this) : Resolve(type, index); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private object Resolve(Type type, int index) + { + var finish = index + _bucketSize; + while (++index < finish) + { + ref var pair = ref _buckets[index]; + if (pair.Key == type) + { + return pair.Value.Resolve(this); + } + } + + throw new InvalidOperationException($"{CannotResolveMessage} {OfTypeMessage} {type}."); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public object Resolve(Type type, object? tag) + { + var index = (int)(_bucketSize * ((uint)RuntimeHelpers.GetHashCode(type) % 1)); + ref var pair = ref _buckets[index]; + return pair.Key == type ? pair.Value.ResolveByTag(this, tag) : Resolve(type, tag, index); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private object Resolve(Type type, object? tag, int index) + { + var finish = index + _bucketSize; + while (++index < finish) + { + ref var pair = ref _buckets[index]; + if (pair.Key == type) + { + return pair.Value.ResolveByTag(this, tag); + } + } + + throw new InvalidOperationException($"{CannotResolveMessage} \"{tag}\" {OfTypeMessage} {type}."); + } + + private readonly static int _bucketSize; + private readonly static Pair>[] _buckets; + + static Composition() + { + var valResolver_0000 = new Resolver_0000(); + Resolver.Value = valResolver_0000; + _buckets = Buckets>.Create( + 1, + out _bucketSize, + new Pair>[1] + { + new Pair>(typeof(Program), valResolver_0000) + }); + } + + private const string CannotResolveMessage = "Cannot resolve composition root "; + private const string OfTypeMessage = "of type "; + + private class Resolver: IResolver + { + public static IResolver Value = new Resolver(); + + public virtual T Resolve(Composition composite) + { + throw new InvalidOperationException($"{CannotResolveMessage}{OfTypeMessage}{typeof(T)}."); + } + + public virtual T ResolveByTag(Composition composite, object tag) + { + throw new InvalidOperationException($"{CannotResolveMessage}\"{tag}\" {OfTypeMessage}{typeof(T)}."); + } + } + + private sealed class Resolver_0000: Resolver + { + public override Program Resolve(Composition composition) + { + return composition.Program; + } + + public override Program ResolveByTag(Composition composition, object tag) + { + switch (tag) + { + case null: + return composition.Program; + + default: + return base.ResolveByTag(composition, tag); + } + } + } +} +``` + + diff --git a/readme/exposed-roots-via-root-arg.md b/readme/exposed-roots-via-root-arg.md new file mode 100644 index 000000000..8b35052ed --- /dev/null +++ b/readme/exposed-roots-via-root-arg.md @@ -0,0 +1,80 @@ +#### Exposed roots via root arg + +[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaRootArgScenario.cs) + +Composition roots from other assemblies or projects can be used as a source of bindings passed through root arguments. When you add a binding to a composition from another assembly or project, the roots of the composition with the `RootKind.Exposed` type will be used in the bindings automatically. For example, in some assembly a composition is defined as: +```c# +public partial class CompositionInOtherProject +{ + private static void Setup() => + DI.Setup() + .Bind().As(Lifetime.Singleton).To() + .Bind().To() + .Root("MyService", kind: RootKinds.Exposed); +} +``` + + +```c# +interface IDependency; + +class Dependency : IDependency; + +interface IService; + +class Service(IDependency dependency) : IService; + +class Program(IService service, IMyService myService) +{ + public IService Service { get; } = service; + + public void DoSomething() => myService.DoSomething(); +} + +DI.Setup(nameof(Composition)) + .Hint(Hint.Resolve, "Off") + .Bind().To() + .Bind().To() + // Binds to exposed composition roots from other project + .RootArg("baseComposition") + .Root("GetProgram"); + +var baseComposition = new CompositionInOtherProject(); +var composition = new Composition(); +var program = composition.GetProgram(baseComposition); +program.DoSomething(); +``` + +The following partial class will be generated: + +```c# +partial class Composition +{ + private readonly Composition _root; + + [OrdinalAttribute(10)] + public Composition() + { + _root = this; + } + + internal Composition(Composition parentScope) + { + _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Program GetProgram(Integration.CompositionInOtherProject baseComposition) + { + Integration.IMyService transientIMyService2; + { + Integration.CompositionInOtherProject localValue5 = baseComposition; + transientIMyService2 = localValue5.MyService; + } + + return new Program(new Service(new Dependency()), transientIMyService2); + } +} +``` + + diff --git a/readme/exposed-roots-with-tags.md b/readme/exposed-roots-with-tags.md index cafbb2a5c..c973766a5 100644 --- a/readme/exposed-roots-with-tags.md +++ b/readme/exposed-roots-with-tags.md @@ -84,8 +84,8 @@ partial class Composition Integration.IMyService transientIMyService2; { - Integration.CompositionWithTagsInOtherProject localValue4 = _root._singletonCompositionWithTagsInOtherProject41!; - transientIMyService2 = localValue4.MyService; + Integration.CompositionWithTagsInOtherProject localValue6 = _root._singletonCompositionWithTagsInOtherProject41!; + transientIMyService2 = localValue6.MyService; } return new Program(new Service(new Dependency()), transientIMyService2); diff --git a/readme/exposed-roots.md b/readme/exposed-roots.md index 4b4ee01f4..7ea65578f 100644 --- a/readme/exposed-roots.md +++ b/readme/exposed-roots.md @@ -43,6 +43,9 @@ var program = composition.Program; program.DoSomething(); ``` +> [!IMPORTANT] +> At this point, a composition from another assembly or another project can be used for this purpose. Compositions from the current project cannot be used in this way due to limitations of the source code generators. + The following partial class will be generated: ```c# diff --git a/readme/factory.md b/readme/factory.md index 39f1e3b76..a4d0bf417 100644 --- a/readme/factory.md +++ b/readme/factory.md @@ -91,9 +91,9 @@ partial class Composition DateTimeOffset transientDateTimeOffset3 = DateTimeOffset.Now; Dependency transientDependency1; { - Dependency localDependency22 = new Dependency(transientDateTimeOffset3); - localDependency22.Initialize(); - transientDependency1 = localDependency22; + Dependency localDependency24 = new Dependency(transientDateTimeOffset3); + localDependency24.Initialize(); + transientDependency1 = localDependency24; } return new Service(transientDependency1); diff --git a/readme/func-with-arguments.md b/readme/func-with-arguments.md index 5538c25fd..cb97a7ae7 100644 --- a/readme/func-with-arguments.md +++ b/readme/func-with-arguments.md @@ -126,8 +126,8 @@ partial class Composition } } - Dependency localDependency24 = new Dependency(_root._singletonClock39!, transientInt323, transientInt324); - return localDependency24; + Dependency localDependency26 = new Dependency(_root._singletonClock39!, transientInt323, transientInt324); + return localDependency26; }; return new Service(transientFunc1); } diff --git a/readme/func-with-tag.md b/readme/func-with-tag.md index f86b26796..cd1961e67 100644 --- a/readme/func-with-tag.md +++ b/readme/func-with-tag.md @@ -73,8 +73,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - IDependency localValue25 = new Dependency(); - return localValue25; + IDependency localValue27 = new Dependency(); + return localValue27; }); } } diff --git a/readme/func.md b/readme/func.md index 0ef03c3af..2d1d9c968 100644 --- a/readme/func.md +++ b/readme/func.md @@ -76,8 +76,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - IDependency localValue23 = new Dependency(); - return localValue23; + IDependency localValue25 = new Dependency(); + return localValue25; }); } } diff --git a/readme/generic-async-composition-roots-with-constraints.md b/readme/generic-async-composition-roots-with-constraints.md index 5492b38f3..8a8f2d5f7 100644 --- a/readme/generic-async-composition-roots-with-constraints.md +++ b/readme/generic-async-composition-roots-with-constraints.md @@ -93,11 +93,11 @@ partial class Composition TaskCreationOptions transientTaskCreationOptions2 = TaskCreationOptions.None; TaskFactory> perBlockTaskFactory1; { - CancellationToken localCancellationToken39 = cancellationToken; - TaskCreationOptions localTaskCreationOptions40 = transientTaskCreationOptions2; - TaskContinuationOptions localTaskContinuationOptions41 = transientTaskContinuationOptions3; - TaskScheduler localTaskScheduler42 = transientTaskScheduler4; - perBlockTaskFactory1 = new TaskFactory>(localCancellationToken39, localTaskCreationOptions40, localTaskContinuationOptions41, localTaskScheduler42); + CancellationToken localCancellationToken41 = cancellationToken; + TaskCreationOptions localTaskCreationOptions42 = transientTaskCreationOptions2; + TaskContinuationOptions localTaskContinuationOptions43 = transientTaskContinuationOptions3; + TaskScheduler localTaskScheduler44 = transientTaskScheduler4; + perBlockTaskFactory1 = new TaskFactory>(localCancellationToken41, localTaskCreationOptions42, localTaskContinuationOptions43, localTaskScheduler44); } if (perResolveFunc48 == null) @@ -112,12 +112,12 @@ partial class Composition { OtherService transientOtherService5; { - IDependency localDependency44 = new Dependency(); - transientOtherService5 = new OtherService(localDependency44); + IDependency localDependency46 = new Dependency(); + transientOtherService5 = new OtherService(localDependency46); } - IService localValue43 = transientOtherService5; - return localValue43; + IService localValue45 = transientOtherService5; + return localValue45; }); } } @@ -125,9 +125,9 @@ partial class Composition Task> transientTask0; { - Func> localFactory45 = perResolveFunc48!; - TaskFactory> localTaskFactory46 = perBlockTaskFactory1; - transientTask0 = localTaskFactory46.StartNew(localFactory45); + Func> localFactory47 = perResolveFunc48!; + TaskFactory> localTaskFactory48 = perBlockTaskFactory1; + transientTask0 = localTaskFactory48.StartNew(localFactory47); } return transientTask0; @@ -144,11 +144,11 @@ partial class Composition TaskCreationOptions transientTaskCreationOptions2 = TaskCreationOptions.None; TaskFactory> perBlockTaskFactory1; { - CancellationToken localCancellationToken47 = cancellationToken; - TaskCreationOptions localTaskCreationOptions48 = transientTaskCreationOptions2; - TaskContinuationOptions localTaskContinuationOptions49 = transientTaskContinuationOptions3; - TaskScheduler localTaskScheduler50 = transientTaskScheduler4; - perBlockTaskFactory1 = new TaskFactory>(localCancellationToken47, localTaskCreationOptions48, localTaskContinuationOptions49, localTaskScheduler50); + CancellationToken localCancellationToken49 = cancellationToken; + TaskCreationOptions localTaskCreationOptions50 = transientTaskCreationOptions2; + TaskContinuationOptions localTaskContinuationOptions51 = transientTaskContinuationOptions3; + TaskScheduler localTaskScheduler52 = transientTaskScheduler4; + perBlockTaskFactory1 = new TaskFactory>(localCancellationToken49, localTaskCreationOptions50, localTaskContinuationOptions51, localTaskScheduler52); } if (perResolveFunc50 == null) @@ -161,8 +161,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - IService localValue51 = new Service(new Dependency()); - return localValue51; + IService localValue53 = new Service(new Dependency()); + return localValue53; }); } } @@ -170,9 +170,9 @@ partial class Composition Task> transientTask0; { - Func> localFactory52 = perResolveFunc50!; - TaskFactory> localTaskFactory53 = perBlockTaskFactory1; - transientTask0 = localTaskFactory53.StartNew(localFactory52); + Func> localFactory54 = perResolveFunc50!; + TaskFactory> localTaskFactory55 = perBlockTaskFactory1; + transientTask0 = localTaskFactory55.StartNew(localFactory54); } return transientTask0; diff --git a/readme/generic-composition-roots-with-constraints.md b/readme/generic-composition-roots-with-constraints.md index 3efb0879e..7990e44b1 100644 --- a/readme/generic-composition-roots-with-constraints.md +++ b/readme/generic-composition-roots-with-constraints.md @@ -84,8 +84,8 @@ partial class Composition { OtherService transientOtherService0; { - IDependency localDependency54 = new Dependency(); - transientOtherService0 = new OtherService(localDependency54); + IDependency localDependency56 = new Dependency(); + transientOtherService0 = new OtherService(localDependency56); } return transientOtherService0; diff --git a/readme/generic-composition-roots.md b/readme/generic-composition-roots.md index 923405f6c..5d0f541a2 100644 --- a/readme/generic-composition-roots.md +++ b/readme/generic-composition-roots.md @@ -77,8 +77,8 @@ partial class Composition { OtherService transientOtherService0; { - IDependency localDependency55 = new Dependency(); - transientOtherService0 = new OtherService(localDependency55); + IDependency localDependency57 = new Dependency(); + transientOtherService0 = new OtherService(localDependency57); } return transientOtherService0; diff --git a/readme/lazy.md b/readme/lazy.md index 1446f8133..b450fff5f 100644 --- a/readme/lazy.md +++ b/readme/lazy.md @@ -67,8 +67,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - IDependency localValue26 = new Dependency(); - return localValue26; + IDependency localValue28 = new Dependency(); + return localValue28; }); } } @@ -76,8 +76,8 @@ partial class Composition Lazy transientLazy1; { - Func localFactory27 = perResolveFunc43!; - transientLazy1 = new Lazy(localFactory27, true); + Func localFactory29 = perResolveFunc43!; + transientLazy1 = new Lazy(localFactory29, true); } return new Service(transientLazy1); diff --git a/readme/manually-started-tasks.md b/readme/manually-started-tasks.md index cd9e74668..feb752ae8 100644 --- a/readme/manually-started-tasks.md +++ b/readme/manually-started-tasks.md @@ -105,8 +105,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - IDependency localValue28 = new Dependency(); - return localValue28; + IDependency localValue30 = new Dependency(); + return localValue30; }); } } @@ -114,9 +114,9 @@ partial class Composition Task transientTask1; { - Func localFactory29 = perResolveFunc45!; - CancellationToken localCancellationToken30 = cancellationToken; - transientTask1 = new Task(localFactory29, localCancellationToken30); + Func localFactory31 = perResolveFunc45!; + CancellationToken localCancellationToken32 = cancellationToken; + transientTask1 = new Task(localFactory31, localCancellationToken32); } return new Service(transientTask1); diff --git a/readme/scope.md b/readme/scope.md index 74445ec0d..21b50392c 100644 --- a/readme/scope.md +++ b/readme/scope.md @@ -146,8 +146,8 @@ partial class Composition: IDisposable () => { Composition transientComposition2 = this; - Session localValue60 = new Session(transientComposition2); - return localValue60; + Session localValue62 = new Session(transientComposition2); + return localValue62; }); } } diff --git a/readme/task.md b/readme/task.md index 30be02a0c..64627b2e8 100644 --- a/readme/task.md +++ b/readme/task.md @@ -88,11 +88,11 @@ partial class Composition TaskCreationOptions transientTaskCreationOptions3 = TaskCreationOptions.None; TaskFactory perBlockTaskFactory2; { - CancellationToken localCancellationToken31 = cancellationToken; - TaskCreationOptions localTaskCreationOptions32 = transientTaskCreationOptions3; - TaskContinuationOptions localTaskContinuationOptions33 = transientTaskContinuationOptions4; - TaskScheduler localTaskScheduler34 = transientTaskScheduler5; - perBlockTaskFactory2 = new TaskFactory(localCancellationToken31, localTaskCreationOptions32, localTaskContinuationOptions33, localTaskScheduler34); + CancellationToken localCancellationToken33 = cancellationToken; + TaskCreationOptions localTaskCreationOptions34 = transientTaskCreationOptions3; + TaskContinuationOptions localTaskContinuationOptions35 = transientTaskContinuationOptions4; + TaskScheduler localTaskScheduler36 = transientTaskScheduler5; + perBlockTaskFactory2 = new TaskFactory(localCancellationToken33, localTaskCreationOptions34, localTaskContinuationOptions35, localTaskScheduler36); } if (perResolveFunc45 == null) @@ -105,8 +105,8 @@ partial class Composition [MethodImpl(MethodImplOptions.AggressiveInlining)] () => { - IDependency localValue35 = new Dependency(); - return localValue35; + IDependency localValue37 = new Dependency(); + return localValue37; }); } } @@ -114,9 +114,9 @@ partial class Composition Task transientTask1; { - Func localFactory36 = perResolveFunc45!; - TaskFactory localTaskFactory37 = perBlockTaskFactory2; - transientTask1 = localTaskFactory37.StartNew(localFactory36); + Func localFactory38 = perResolveFunc45!; + TaskFactory localTaskFactory39 = perBlockTaskFactory2; + transientTask1 = localTaskFactory39.StartNew(localFactory38); } return new Service(transientTask1); diff --git a/readme/tracking-async-disposable-instances-in-delegates.md b/readme/tracking-async-disposable-instances-in-delegates.md index 4fc3e0ee5..de75f739d 100644 --- a/readme/tracking-async-disposable-instances-in-delegates.md +++ b/readme/tracking-async-disposable-instances-in-delegates.md @@ -116,9 +116,9 @@ partial class Composition Owned perBlockOwned1; { - Owned localOwned6 = accumulator41; - IDependency localValue7 = transientDependency3; - perBlockOwned1 = new Owned(localValue7, localOwned6); + Owned localOwned8 = accumulator41; + IDependency localValue9 = transientDependency3; + perBlockOwned1 = new Owned(localValue9, localOwned8); } lock (_lock) @@ -126,8 +126,8 @@ partial class Composition accumulator41.Add(perBlockOwned1); } - Owned localValue5 = perBlockOwned1; - return localValue5; + Owned localValue7 = perBlockOwned1; + return localValue7; }); } } diff --git a/readme/tracking-async-disposable-instances-per-a-composition-root.md b/readme/tracking-async-disposable-instances-per-a-composition-root.md index 918d8ccad..48f1eef42 100644 --- a/readme/tracking-async-disposable-instances-per-a-composition-root.md +++ b/readme/tracking-async-disposable-instances-per-a-composition-root.md @@ -98,9 +98,9 @@ partial class Composition Owned perBlockOwned0; { - Owned localOwned8 = accumulator42; - IService localValue9 = new Service(transientDependency3); - perBlockOwned0 = new Owned(localValue9, localOwned8); + Owned localOwned10 = accumulator42; + IService localValue11 = new Service(transientDependency3); + perBlockOwned0 = new Owned(localValue11, localOwned10); } lock (_lock) diff --git a/readme/tracking-disposable-instances-in-delegates.md b/readme/tracking-disposable-instances-in-delegates.md index 030b96f04..33ddc1382 100644 --- a/readme/tracking-disposable-instances-in-delegates.md +++ b/readme/tracking-disposable-instances-in-delegates.md @@ -109,9 +109,9 @@ partial class Composition Owned perBlockOwned1; { - Owned localOwned11 = accumulator41; - IDependency localValue12 = transientDependency3; - perBlockOwned1 = new Owned(localValue12, localOwned11); + Owned localOwned13 = accumulator41; + IDependency localValue14 = transientDependency3; + perBlockOwned1 = new Owned(localValue14, localOwned13); } lock (_lock) @@ -119,8 +119,8 @@ partial class Composition accumulator41.Add(perBlockOwned1); } - Owned localValue10 = perBlockOwned1; - return localValue10; + Owned localValue12 = perBlockOwned1; + return localValue12; }); } } diff --git a/readme/tracking-disposable-instances-per-a-composition-root.md b/readme/tracking-disposable-instances-per-a-composition-root.md index d7c208acc..3f11f4ad3 100644 --- a/readme/tracking-disposable-instances-per-a-composition-root.md +++ b/readme/tracking-disposable-instances-per-a-composition-root.md @@ -94,9 +94,9 @@ partial class Composition Owned perBlockOwned0; { - Owned localOwned13 = accumulator42; - IService localValue14 = new Service(transientDependency3); - perBlockOwned0 = new Owned(localValue14, localOwned13); + Owned localOwned15 = accumulator42; + IService localValue16 = new Service(transientDependency3); + perBlockOwned0 = new Owned(localValue16, localOwned15); } lock (_lock) diff --git a/readme/valuetask.md b/readme/valuetask.md index e851af0c3..381380dbd 100644 --- a/readme/valuetask.md +++ b/readme/valuetask.md @@ -65,8 +65,8 @@ partial class Composition { ValueTask transientValueTask1; { - IDependency localValue38 = new Dependency(); - transientValueTask1 = new ValueTask(localValue38); + IDependency localValue40 = new Dependency(); + transientValueTask1 = new ValueTask(localValue40); } return new Service(transientValueTask1); diff --git a/tests/Pure.DI.UsageTests/Advanced/ExposedGenericRootsScenario.cs b/tests/Pure.DI.UsageTests/Advanced/ExposedGenericRootsScenario.cs index d7bfbe08f..8c67942e8 100644 --- a/tests/Pure.DI.UsageTests/Advanced/ExposedGenericRootsScenario.cs +++ b/tests/Pure.DI.UsageTests/Advanced/ExposedGenericRootsScenario.cs @@ -15,6 +15,8 @@ $h= .Root>("GetMyService", kind: RootKinds.Exposed); $h=} $h=``` +$f=> [!IMPORTANT] +$f=> At this point, a composition from another assembly or another project can be used for this purpose. Compositions from the current project cannot be used in this way due to limitations of the source code generators. */ // ReSharper disable ClassNeverInstantiated.Local diff --git a/tests/Pure.DI.UsageTests/Advanced/ExposedRootsScenario.cs b/tests/Pure.DI.UsageTests/Advanced/ExposedRootsScenario.cs index 01e807965..383e59fa5 100644 --- a/tests/Pure.DI.UsageTests/Advanced/ExposedRootsScenario.cs +++ b/tests/Pure.DI.UsageTests/Advanced/ExposedRootsScenario.cs @@ -13,6 +13,8 @@ $h= .Root("MyService", kind: RootKinds.Exposed); $h=} $h=``` +$f=> [!IMPORTANT] +$f=> At this point, a composition from another assembly or another project can be used for this purpose. Compositions from the current project cannot be used in this way due to limitations of the source code generators. */ // ReSharper disable ClassNeverInstantiated.Local diff --git a/tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaArgScenario.cs b/tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaArgScenario.cs new file mode 100644 index 000000000..b279b7cf0 --- /dev/null +++ b/tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaArgScenario.cs @@ -0,0 +1,66 @@ +/* +$v=true +$p=202 +$d=Exposed roots via arg +$h=Composition roots from other assemblies or projects can be used as a source of bindings passed through class arguments. When you add a binding to a composition from another assembly or project, the roots of the composition with the `RootKind.Exposed` type will be used in the bindings automatically. For example, in some assembly a composition is defined as: +$h=```c# +$h=public partial class CompositionInOtherProject +$h={ +$h= private static void Setup() => +$h= DI.Setup() +$h= .Bind().As(Lifetime.Singleton).To() +$h= .Bind().To() +$h= .Root("MyService", kind: RootKinds.Exposed); +$h=} +$h=``` +*/ + +// ReSharper disable ClassNeverInstantiated.Local +// ReSharper disable CheckNamespace +// ReSharper disable UnusedParameter.Local +// ReSharper disable RedundantAssignment +// ReSharper disable ArrangeTypeModifiers +#pragma warning disable CS9113 // Parameter is unread. +namespace Pure.DI.UsageTests.Advanced.ExposedRootsViaArgScenario; + +using Integration; +using Pure.DI; +using Xunit; + +// { +interface IDependency; + +class Dependency : IDependency; + +interface IService; + +class Service(IDependency dependency) : IService; + +class Program(IService service, IMyService myService) +{ + public IService Service { get; } = service; + + public void DoSomething() => myService.DoSomething(); +} +// } + +public class Scenario +{ + [Fact] + public void Run() + { +// { + DI.Setup(nameof(Composition)) + .Bind().To() + .Bind().To() + // Binds to exposed composition roots from other project + .Arg("baseComposition") + .Root("Program"); + + var baseComposition = new CompositionInOtherProject(); + var composition = new Composition(baseComposition); + var program = composition.Program; + program.DoSomething(); +// } + } +} \ No newline at end of file diff --git a/tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaRootArgScenario.cs b/tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaRootArgScenario.cs new file mode 100644 index 000000000..3d99d187d --- /dev/null +++ b/tests/Pure.DI.UsageTests/Advanced/ExposedRootsViaRootArgScenario.cs @@ -0,0 +1,67 @@ +/* +$v=true +$p=203 +$d=Exposed roots via root arg +$h=Composition roots from other assemblies or projects can be used as a source of bindings passed through root arguments. When you add a binding to a composition from another assembly or project, the roots of the composition with the `RootKind.Exposed` type will be used in the bindings automatically. For example, in some assembly a composition is defined as: +$h=```c# +$h=public partial class CompositionInOtherProject +$h={ +$h= private static void Setup() => +$h= DI.Setup() +$h= .Bind().As(Lifetime.Singleton).To() +$h= .Bind().To() +$h= .Root("MyService", kind: RootKinds.Exposed); +$h=} +$h=``` +*/ + +// ReSharper disable ClassNeverInstantiated.Local +// ReSharper disable CheckNamespace +// ReSharper disable UnusedParameter.Local +// ReSharper disable RedundantAssignment +// ReSharper disable ArrangeTypeModifiers +#pragma warning disable CS9113 // Parameter is unread. +namespace Pure.DI.UsageTests.Advanced.ExposedRootsViaRootArgScenario; + +using Integration; +using Pure.DI; +using Xunit; + +// { +interface IDependency; + +class Dependency : IDependency; + +interface IService; + +class Service(IDependency dependency) : IService; + +class Program(IService service, IMyService myService) +{ + public IService Service { get; } = service; + + public void DoSomething() => myService.DoSomething(); +} +// } + +public class Scenario +{ + [Fact] + public void Run() + { +// { + DI.Setup(nameof(Composition)) + .Hint(Hint.Resolve, "Off") + .Bind().To() + .Bind().To() + // Binds to exposed composition roots from other project + .RootArg("baseComposition") + .Root("GetProgram"); + + var baseComposition = new CompositionInOtherProject(); + var composition = new Composition(); + var program = composition.GetProgram(baseComposition); + program.DoSomething(); +// } + } +} \ No newline at end of file