From d43d711da12d6b1e396dd39ef5b1d445eb7606d6 Mon Sep 17 00:00:00 2001 From: Nikolay Pianikov Date: Thu, 9 May 2024 10:06:48 +0300 Subject: [PATCH] Update README.md --- README.md | 14 +- readme/composition-roots-simplified.md | 269 ------------------ readme/composition-roots.md | 26 +- readme/constructor-ordinal-attribute.md | 2 + readme/default-lifetime.md | 4 + readme/default-values.md | 2 + readme/factory.md | 7 + readme/field-injection.md | 3 + readme/injection.md | 245 ---------------- readme/injections-of-abstractions.md | 2 +- readme/instance-initialization.md | 266 ----------------- readme/member-ordinal-attribute.md | 3 + readme/method-injection.md | 3 + readme/multi-contract-bindings.md | 248 ---------------- readme/property-injection.md | 3 + readme/required-properties-or-fields.md | 2 + readme/resolve-methods.md | 2 +- readme/{rootbind.md => root-binding.md} | 2 +- ...async-disposable-instances-in-delegates.md | 2 +- ...osable-instances-per-a-composition-root.md | 2 +- ...cking-disposable-instances-in-delegates.md | 2 +- ...osable-instances-per-a-composition-root.md | 2 +- .../InstanceInitializationScenario.cs | 75 ----- ...ckingAsyncDisposableInDelegatesScenario.cs | 2 +- .../TrackingAsyncDisposableScenario.cs | 2 +- .../TrackingDisposableInDelegatesScenario.cs | 2 +- .../TrackingDisposableScenario.cs | 2 +- .../ConstructorOrdinalAttributeScenario.cs | 2 + .../MemberOrdinalAttributeScenario.cs | 3 + .../Basics/CompositionRootsScenario.cs | 14 +- .../CompositionRootsSimplifiedScenario.cs | 64 ----- .../Basics/DefaultValuesScenario.cs | 2 + .../Basics/FactoryScenario.cs | 7 + .../Basics/FieldInjectionScenario.cs | 3 + .../Basics/InjectionScenario.cs | 58 ---- .../InjectionsOfAbstractionsScenario.cs | 2 +- .../Basics/MethodInjectionScenario.cs | 3 + .../Basics/MultiContractBindingsScenario.cs | 53 ---- .../Basics/PropertyInjectionScenario.cs | 3 + .../RequiredPropertiesOrFieldsScenario.cs | 2 + ...eScenario.cs => ResolveMethodsScenario.cs} | 2 +- .../Basics/RootBindScenario.cs | 2 +- .../Lifetimes/DefaultLifetimeScenario.cs | 4 + 43 files changed, 99 insertions(+), 1319 deletions(-) delete mode 100644 readme/composition-roots-simplified.md delete mode 100644 readme/injection.md delete mode 100644 readme/instance-initialization.md delete mode 100644 readme/multi-contract-bindings.md rename readme/{rootbind.md => root-binding.md} (99%) delete mode 100644 tests/Pure.DI.UsageTests/Advanced/InstanceInitializationScenario.cs rename tests/Pure.DI.UsageTests/{Basics => Advanced}/TrackingAsyncDisposableInDelegatesScenario.cs (96%) rename tests/Pure.DI.UsageTests/{Basics => Advanced}/TrackingAsyncDisposableScenario.cs (96%) rename tests/Pure.DI.UsageTests/{Basics => Advanced}/TrackingDisposableInDelegatesScenario.cs (96%) rename tests/Pure.DI.UsageTests/{Basics => Advanced}/TrackingDisposableScenario.cs (96%) delete mode 100644 tests/Pure.DI.UsageTests/Basics/CompositionRootsSimplifiedScenario.cs delete mode 100644 tests/Pure.DI.UsageTests/Basics/InjectionScenario.cs delete mode 100644 tests/Pure.DI.UsageTests/Basics/MultiContractBindingsScenario.cs rename tests/Pure.DI.UsageTests/Basics/{ResolveScenario.cs => ResolveMethodsScenario.cs} (97%) diff --git a/README.md b/README.md index c2c4bd37e..5f8fca556 100644 --- a/README.md +++ b/README.md @@ -197,25 +197,18 @@ dotnet run - [Auto-bindings](readme/auto-bindings.md) - [Injections of abstractions](readme/injections-of-abstractions.md) - [Composition roots](readme/composition-roots.md) -- [Composition roots simplified](readme/composition-roots-simplified.md) - [Resolve methods](readme/resolve-methods.md) - [Simplified binding](readme/simplified-binding.md) - [Factory](readme/factory.md) -- [Injection](readme/injection.md) - [Arguments](readme/arguments.md) - [Root arguments](readme/root-arguments.md) - [Tags](readme/tags.md) -- [Multi-contract bindings](readme/multi-contract-bindings.md) - [Field injection](readme/field-injection.md) - [Method injection](readme/method-injection.md) - [Property injection](readme/property-injection.md) - [Default values](readme/default-values.md) - [Required properties or fields](readme/required-properties-or-fields.md) -- [Tracking async disposable instances in delegates](readme/tracking-async-disposable-instances-in-delegates.md) -- [Tracking disposable instances in delegates](readme/tracking-disposable-instances-in-delegates.md) -- [Tracking disposable instances per a composition root](readme/tracking-disposable-instances-per-a-composition-root.md) -- [RootBind](readme/rootbind.md) -- [Tracking async disposable instances per a composition root](readme/tracking-async-disposable-instances-per-a-composition-root.md) +- [Root binding](readme/root-binding.md) ### Lifetimes - [Singleton](readme/singleton.md) - [PerResolve](readme/perresolve.md) @@ -272,7 +265,6 @@ dotnet run - [Check for a root](readme/check-for-a-root.md) ### Advanced - [Composition root kinds](readme/composition-root-kinds.md) -- [Instance Initialization](readme/instance-initialization.md) - [Tag Type](readme/tag-type.md) - [Tag Unique](readme/tag-unique.md) - [A few partial classes](readme/a-few-partial-classes.md) @@ -280,6 +272,10 @@ dotnet run - [Dependent compositions](readme/dependent-compositions.md) - [Accumulators](readme/accumulators.md) - [Global compositions](readme/global-compositions.md) +- [Tracking async disposable instances in delegates](readme/tracking-async-disposable-instances-in-delegates.md) +- [Tracking disposable instances in delegates](readme/tracking-disposable-instances-in-delegates.md) +- [Tracking disposable instances per a composition root](readme/tracking-disposable-instances-per-a-composition-root.md) +- [Tracking async disposable instances per a composition root](readme/tracking-async-disposable-instances-per-a-composition-root.md) ### Applications - Console - [Schrödinger's cat](readme/Console.md) diff --git a/readme/composition-roots-simplified.md b/readme/composition-roots-simplified.md deleted file mode 100644 index 4c1ca5d28..000000000 --- a/readme/composition-roots-simplified.md +++ /dev/null @@ -1,269 +0,0 @@ -#### Composition roots simplified - -[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/CompositionRootsSimplifiedScenario.cs) - -You can use `RootBind()` method in order to reduce repetitions. - -```c# -interface IDependency; - -class Dependency : IDependency; - -interface IService; - -class Service(IDependency dependency) : IService; - -class OtherService : IService; - -DI.Setup(nameof(Composition)) - // Specifies to create a regular public composition root - // of type "IService" with the name "MyRoot" and - // it's the equivalent of statements - // .Bind().To().Root("MyRoot") - .RootBind("MyRoot").To() - - // Specifies to create a private composition root - // that is only accessible from "Resolve()" methods and - // it's the equivalent of statements - // .Bind("Other").To().Root("MyRoot") - .RootBind(tags: "Other").To() - - .Bind().To(); - -var composition = new Composition(); - -// service = new Service(new Dependency()); -var service = composition.MyRoot; - -// someOtherService = new OtherService(); -var someOtherService = composition.Resolve("Other"); -``` - -
-Class Diagram - -```mermaid -classDiagram - class Composition { - +IService MyRoot - -IService _ - + T ResolveᐸTᐳ() - + T ResolveᐸTᐳ(object? tag) - + object Resolve(Type type) - + object Resolve(Type type, object? tag) - } - Service --|> IService : - class Service { - +Service(IDependency dependency) - } - OtherService --|> IService : "Other" - class OtherService { - +OtherService() - } - Dependency --|> IDependency : - class Dependency { - +Dependency() - } - class IService { - <> - } - class IDependency { - <> - } - Service *-- Dependency : IDependency - Composition ..> Service : IService MyRoot - Composition ..> OtherService : IService _ -``` - -
- -
-Pure.DI-generated partial class Composition
- -```c# -partial class Composition -{ - private readonly Composition _root; - - public Composition() - { - _root = this; - } - - internal Composition(Composition parentScope) - { - _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; - } - - public IService MyRoot - { - [MethodImpl((MethodImplOptions)0x100)] - get - { - return new Service(new Dependency()); - } - } - - private IService Root0002 - { - [MethodImpl((MethodImplOptions)0x100)] - get - { - return new OtherService(); - } - } - - [MethodImpl((MethodImplOptions)0x100)] - public T Resolve() - { - return Resolver.Value.Resolve(this); - } - - [MethodImpl((MethodImplOptions)0x100)] - public T Resolve(object? tag) - { - return Resolver.Value.ResolveByTag(this, tag); - } - - [MethodImpl((MethodImplOptions)0x100)] - 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)0x8)] - 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)0x100)] - 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)0x8)] - 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}."); - } - - public override string ToString() - { - return - "classDiagram\n" + - " class Composition {\n" + - " +IService MyRoot\n" + - " -IService _\n" + - " + T ResolveᐸTᐳ()\n" + - " + T ResolveᐸTᐳ(object? tag)\n" + - " + object Resolve(Type type)\n" + - " + object Resolve(Type type, object? tag)\n" + - " }\n" + - " Service --|> IService : \n" + - " class Service {\n" + - " +Service(IDependency dependency)\n" + - " }\n" + - " OtherService --|> IService : \"Other\" \n" + - " class OtherService {\n" + - " +OtherService()\n" + - " }\n" + - " Dependency --|> IDependency : \n" + - " class Dependency {\n" + - " +Dependency()\n" + - " }\n" + - " class IService {\n" + - " <>\n" + - " }\n" + - " class IDependency {\n" + - " <>\n" + - " }\n" + - " Service *-- Dependency : IDependency\n" + - " Composition ..> Service : IService MyRoot\n" + - " Composition ..> OtherService : IService _"; - } - - 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(IService), 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 IService Resolve(Composition composition) - { - return composition.MyRoot; - } - - public override IService ResolveByTag(Composition composition, object tag) - { - switch (tag) - { - case "Other": - return composition.Root0002; - case null: - return composition.MyRoot; - default: - return base.ResolveByTag(composition, tag); - } - } - } -} -``` - -
- diff --git a/readme/composition-roots.md b/readme/composition-roots.md index 89bed2cf8..677b49dbe 100644 --- a/readme/composition-roots.md +++ b/readme/composition-roots.md @@ -20,18 +20,18 @@ DI.Setup(nameof(Composition)) .Bind("Other").To() .Bind().To() - // Specifies to create a regular public composition root - // of type "IService" with the name "SomeOtherService" - // using the "Other" tag - .Root("SomeOtherService", "Other") - // Specifies to create a regular public composition root // of type "IService" with the name "MyRoot" .Root("MyRoot") // Specifies to create a private composition root // that is only accessible from "Resolve()" methods - .Root(); + .Root() + + // Specifies to create a regular public composition root + // of type "IService" with the name "SomeOtherService" + // using the "Other" tag + .Root("SomeOtherService", "Other"); var composition = new Composition(); @@ -41,6 +41,8 @@ var service = composition.MyRoot; // someOtherService = new OtherService(); var someOtherService = composition.SomeOtherService; +// All and only the roots of the composition +// can be obtained by Resolve method var dependency = composition.Resolve(); ``` @@ -96,9 +98,9 @@ classDiagram <> } Service *-- Dependency : IDependency - Composition ..> OtherService : IService SomeOtherService Composition ..> Service : IService MyRoot Composition ..> Dependency : IDependency _ + Composition ..> OtherService : IService SomeOtherService ``` @@ -139,7 +141,7 @@ partial class Composition } } - private IDependency Root0003 + private IDependency Root0002 { [MethodImpl((MethodImplOptions)0x100)] get @@ -240,9 +242,9 @@ partial class Composition " <>\n" + " }\n" + " Service *-- Dependency : IDependency\n" + - " Composition ..> OtherService : IService SomeOtherService\n" + " Composition ..> Service : IService MyRoot\n" + - " Composition ..> Dependency : IDependency _"; + " Composition ..> Dependency : IDependency _\n" + + " Composition ..> OtherService : IService SomeOtherService"; } private readonly static int _bucketSize; @@ -307,7 +309,7 @@ partial class Composition { public override IDependency Resolve(Composition composition) { - return composition.Root0003; + return composition.Root0002; } public override IDependency ResolveByTag(Composition composition, object tag) @@ -315,7 +317,7 @@ partial class Composition switch (tag) { case null: - return composition.Root0003; + return composition.Root0002; default: return base.ResolveByTag(composition, tag); } diff --git a/readme/constructor-ordinal-attribute.md b/readme/constructor-ordinal-attribute.md index ebfecef99..815c39bcc 100644 --- a/readme/constructor-ordinal-attribute.md +++ b/readme/constructor-ordinal-attribute.md @@ -15,6 +15,8 @@ class Service : IService { private readonly string _name; + // The integer value in the argument specifies + // the ordinal of injection [Ordinal(1)] public Service(IDependency dependency) => _name = "with dependency"; diff --git a/readme/default-lifetime.md b/readme/default-lifetime.md index 1aaa0df4f..ef26b17a6 100644 --- a/readme/default-lifetime.md +++ b/readme/default-lifetime.md @@ -27,7 +27,11 @@ class Service( } DI.Setup(nameof(Composition)) + // Default Lifetime applies + // to all bindings until the end of the chain + // or the next call to the DefaultLifetime method .DefaultLifetime(Lifetime.Singleton) + .Bind().To() .RootBind("Root").To(); diff --git a/readme/default-values.md b/readme/default-values.md index 82b0d5a63..42dfde35c 100644 --- a/readme/default-values.md +++ b/readme/default-values.md @@ -14,6 +14,8 @@ interface IService IDependency Dependency { get;} } +// If injection cannot be performed explicitly, +// the default value will be used class Service(string name = "My Service") : IService { public string Name { get; } = name; diff --git a/readme/factory.md b/readme/factory.md index e528d1722..a25333cad 100644 --- a/readme/factory.md +++ b/readme/factory.md @@ -35,8 +35,15 @@ DI.Setup(nameof(Composition)) .Bind().To(_ => DateTimeOffset.Now) .Bind().To(ctx => { + // Some custom logic for creating an instance. + // For example, here's how you can inject + // an instance of a particular type ctx.Inject(out Dependency dependency); + + // And do something about it dependency.Initialize(); + + // And at the end return an instance return dependency; }) .Bind().To() diff --git a/readme/field-injection.md b/readme/field-injection.md index 720077ebb..5cbca1947 100644 --- a/readme/field-injection.md +++ b/readme/field-injection.md @@ -16,6 +16,9 @@ interface IService class Service : IService { + // The Ordinal attribute specifies to perform an injection, + // the integer value in the argument specifies + // the ordinal of injection [Ordinal(0)] internal IDependency? DependencyVal; diff --git a/readme/injection.md b/readme/injection.md deleted file mode 100644 index f348d9d6a..000000000 --- a/readme/injection.md +++ /dev/null @@ -1,245 +0,0 @@ -#### Injection - -[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/InjectionScenario.cs) - -This example shows how to manually create and initialize an instance by injecting the necessary dependencies. - -```c# -interface IDependency; - -class Dependency : IDependency; - -interface IService -{ - IDependency Dependency { get; } -} - -class Service(IDependency dependency) : IService -{ - public IDependency Dependency { get; } = dependency; -} - -DI.Setup(nameof(Composition)) - .Bind().To() - .Bind() - .To(ctx => - { - ctx.Inject(out var dependency); - return new Service(dependency); - }) - - // Composition root - .Root("Root"); - -var composition = new Composition(); -var service = composition.Root; -``` - -In addition to the dependency type, you can specify the dependency tag in the first parameter. Then the overloaded method `void Inject(object tag, out T value)` is used. Where the first argument is the tag, the second is the dependency instance. - -
-Class Diagram - -```mermaid -classDiagram - class Composition { - +IService Root - + T ResolveᐸTᐳ() - + T ResolveᐸTᐳ(object? tag) - + object Resolve(Type type) - + object Resolve(Type type, object? tag) - } - Service --|> IService : - class Service - Dependency --|> IDependency : - class Dependency { - +Dependency() - } - class IService { - <> - } - class IDependency { - <> - } - Service *-- Dependency : IDependency - Composition ..> Service : IService Root -``` - -
- -
-Pure.DI-generated partial class Composition
- -```c# -partial class Composition -{ - private readonly Composition _root; - - public Composition() - { - _root = this; - } - - internal Composition(Composition parentScope) - { - _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; - } - - public IService Root - { - [MethodImpl((MethodImplOptions)0x100)] - get - { - Service transient0_Service; - { - var dependency_1 = new Dependency(); - transient0_Service = new Service(dependency_1); - } - return transient0_Service; - } - } - - [MethodImpl((MethodImplOptions)0x100)] - public T Resolve() - { - return Resolver.Value.Resolve(this); - } - - [MethodImpl((MethodImplOptions)0x100)] - public T Resolve(object? tag) - { - return Resolver.Value.ResolveByTag(this, tag); - } - - [MethodImpl((MethodImplOptions)0x100)] - 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)0x8)] - 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)0x100)] - 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)0x8)] - 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}."); - } - - public override string ToString() - { - return - "classDiagram\n" + - " class Composition {\n" + - " +IService Root\n" + - " + T ResolveᐸTᐳ()\n" + - " + T ResolveᐸTᐳ(object? tag)\n" + - " + object Resolve(Type type)\n" + - " + object Resolve(Type type, object? tag)\n" + - " }\n" + - " Service --|> IService : \n" + - " class Service\n" + - " Dependency --|> IDependency : \n" + - " class Dependency {\n" + - " +Dependency()\n" + - " }\n" + - " class IService {\n" + - " <>\n" + - " }\n" + - " class IDependency {\n" + - " <>\n" + - " }\n" + - " Service *-- Dependency : IDependency\n" + - " Composition ..> Service : IService Root"; - } - - 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(IService), 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 IService Resolve(Composition composition) - { - return composition.Root; - } - - public override IService ResolveByTag(Composition composition, object tag) - { - switch (tag) - { - case null: - return composition.Root; - default: - return base.ResolveByTag(composition, tag); - } - } - } -} -``` - -
- diff --git a/readme/injections-of-abstractions.md b/readme/injections-of-abstractions.md index a4f67d5c1..778648882 100644 --- a/readme/injections-of-abstractions.md +++ b/readme/injections-of-abstractions.md @@ -29,7 +29,7 @@ DI.Setup(nameof(Composition)) .Bind().To() .Bind().To() - // Specifies to create a composition root (a property) + // Specifies to create a composition root // of type "Program" with the name "Root" .Root("Root"); diff --git a/readme/instance-initialization.md b/readme/instance-initialization.md deleted file mode 100644 index b5b28c5cf..000000000 --- a/readme/instance-initialization.md +++ /dev/null @@ -1,266 +0,0 @@ -#### Instance Initialization - -[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Advanced/InstanceInitializationScenario.cs) - -This example shows how to build up an instance with all the necessary dependencies and manually prepare it for further use. - -```c# -interface IDependency; - -class Dependency : IDependency; - -interface IService -{ - string ServiceName { get; } - - IDependency Dependency { get; } - - bool IsInitialized { get; } -} - -class Service(string serviceName, IDependency dependency): IService -{ - public string ServiceName { get; } = serviceName; - - public IDependency Dependency { get; } = dependency; - - public bool IsInitialized { get; private set; } - - public void Initialize() => IsInitialized = true; -} - -DI.Setup(nameof(Composition)) - .Bind().To() - .Arg("serviceName") - .Bind() - .To(ctx => - { - // Builds up an instance with all necessary dependencies - ctx.Inject(out var service); - - // Executing all the necessary logic - // to prepare the instance for further use - service.Initialize(); - return service; - }) - - // Composition root - .Root("Root"); - -var composition = new Composition("My Service"); -var service = composition.Root; -service.ServiceName.ShouldBe("My Service"); -service.IsInitialized.ShouldBeTrue(); -``` - -
-Class Diagram - -```mermaid -classDiagram - class Composition { - +IService Root - + T ResolveᐸTᐳ() - + T ResolveᐸTᐳ(object? tag) - + object Resolve(Type type) - + object Resolve(Type type, object? tag) - } - class Service { - +Service(String serviceName, IDependency dependency) - } - class String - Dependency --|> IDependency : - class Dependency { - +Dependency() - } - class IDependency { - <> - } - Service o-- String : Argument "serviceName" - Service *-- Dependency : IDependency - Composition ..> Service : IService Root -``` - -
- -
-Pure.DI-generated partial class Composition
- -```c# -partial class Composition -{ - private readonly Composition _root; - - private readonly string _arg_serviceName; - - public Composition(string serviceName) - { - _arg_serviceName = serviceName ?? throw new ArgumentNullException(nameof(serviceName)); - _root = this; - } - - internal Composition(Composition parentScope) - { - _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; - _arg_serviceName = _root._arg_serviceName; - } - - public IService Root - { - [MethodImpl((MethodImplOptions)0x100)] - get - { - Service transient0_Service; - { - var service_1 = new Service(_arg_serviceName, new Dependency()); - service_1.Initialize(); - transient0_Service = service_1; - } - return transient0_Service; - } - } - - [MethodImpl((MethodImplOptions)0x100)] - public T Resolve() - { - return Resolver.Value.Resolve(this); - } - - [MethodImpl((MethodImplOptions)0x100)] - public T Resolve(object? tag) - { - return Resolver.Value.ResolveByTag(this, tag); - } - - [MethodImpl((MethodImplOptions)0x100)] - 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)0x8)] - 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)0x100)] - 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)0x8)] - 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}."); - } - - public override string ToString() - { - return - "classDiagram\n" + - " class Composition {\n" + - " +IService Root\n" + - " + T ResolveᐸTᐳ()\n" + - " + T ResolveᐸTᐳ(object? tag)\n" + - " + object Resolve(Type type)\n" + - " + object Resolve(Type type, object? tag)\n" + - " }\n" + - " class Service {\n" + - " +Service(String serviceName, IDependency dependency)\n" + - " }\n" + - " class String\n" + - " Dependency --|> IDependency : \n" + - " class Dependency {\n" + - " +Dependency()\n" + - " }\n" + - " class IDependency {\n" + - " <>\n" + - " }\n" + - " Service o-- String : Argument \"serviceName\"\n" + - " Service *-- Dependency : IDependency\n" + - " Composition ..> Service : IService Root"; - } - - 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(IService), 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 IService Resolve(Composition composition) - { - return composition.Root; - } - - public override IService ResolveByTag(Composition composition, object tag) - { - switch (tag) - { - case null: - return composition.Root; - default: - return base.ResolveByTag(composition, tag); - } - } - } -} -``` - -
- diff --git a/readme/member-ordinal-attribute.md b/readme/member-ordinal-attribute.md index 945f8428b..6e73af510 100644 --- a/readme/member-ordinal-attribute.md +++ b/readme/member-ordinal-attribute.md @@ -16,6 +16,9 @@ class Person : IPerson public string Name => _name.ToString(); + // The Ordinal attribute specifies to perform an injection, + // the integer value in the argument specifies + // the ordinal of injection [Ordinal(0)] public int Id; diff --git a/readme/method-injection.md b/readme/method-injection.md index 55e3ea340..66f959612 100644 --- a/readme/method-injection.md +++ b/readme/method-injection.md @@ -16,6 +16,9 @@ interface IService class Service : IService { + // The Ordinal attribute specifies to perform an injection, + // the integer value in the argument specifies + // the ordinal of injection [Ordinal(0)] public void SetDependency(IDependency dependency) => Dependency = dependency; diff --git a/readme/multi-contract-bindings.md b/readme/multi-contract-bindings.md deleted file mode 100644 index 0dfde6c78..000000000 --- a/readme/multi-contract-bindings.md +++ /dev/null @@ -1,248 +0,0 @@ -#### Multi-contract bindings - -[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/MultiContractBindingsScenario.cs) - -An unlimited number of contracts can be attached to one implementation. Including their combinations with various tags. - -```c# -interface IDependency; - -interface IAdvancedDependency; - -class Dependency : IDependency, IAdvancedDependency; - -interface IService; - -class Service( - IDependency dependency, - IAdvancedDependency advancedDependency) - : IService; - -DI.Setup(nameof(Composition)) - .Bind().To() - // .Bind().Bind().To() - // is also allowed - .Bind().To() - - // Composition root - .Root("Root"); - -var composition = new Composition(); -var service = composition.Root; -``` - -
-Class Diagram - -```mermaid -classDiagram - class Composition { - +IService Root - + T ResolveᐸTᐳ() - + T ResolveᐸTᐳ(object? tag) - + object Resolve(Type type) - + object Resolve(Type type, object? tag) - } - Dependency --|> IDependency : - Dependency --|> IAdvancedDependency : - class Dependency { - +Dependency() - } - Service --|> IService : - class Service { - +Service(IDependency dependency, IAdvancedDependency advancedDependency) - } - class IDependency { - <> - } - class IAdvancedDependency { - <> - } - class IService { - <> - } - Service *-- Dependency : IDependency - Service *-- Dependency : IAdvancedDependency - Composition ..> Service : IService Root -``` - -
- -
-Pure.DI-generated partial class Composition
- -```c# -partial class Composition -{ - private readonly Composition _root; - - public Composition() - { - _root = this; - } - - internal Composition(Composition parentScope) - { - _root = (parentScope ?? throw new ArgumentNullException(nameof(parentScope)))._root; - } - - public IService Root - { - [MethodImpl((MethodImplOptions)0x100)] - get - { - return new Service(new Dependency(), new Dependency()); - } - } - - [MethodImpl((MethodImplOptions)0x100)] - public T Resolve() - { - return Resolver.Value.Resolve(this); - } - - [MethodImpl((MethodImplOptions)0x100)] - public T Resolve(object? tag) - { - return Resolver.Value.ResolveByTag(this, tag); - } - - [MethodImpl((MethodImplOptions)0x100)] - 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)0x8)] - 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)0x100)] - 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)0x8)] - 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}."); - } - - public override string ToString() - { - return - "classDiagram\n" + - " class Composition {\n" + - " +IService Root\n" + - " + T ResolveᐸTᐳ()\n" + - " + T ResolveᐸTᐳ(object? tag)\n" + - " + object Resolve(Type type)\n" + - " + object Resolve(Type type, object? tag)\n" + - " }\n" + - " Dependency --|> IDependency : \n" + - " Dependency --|> IAdvancedDependency : \n" + - " class Dependency {\n" + - " +Dependency()\n" + - " }\n" + - " Service --|> IService : \n" + - " class Service {\n" + - " +Service(IDependency dependency, IAdvancedDependency advancedDependency)\n" + - " }\n" + - " class IDependency {\n" + - " <>\n" + - " }\n" + - " class IAdvancedDependency {\n" + - " <>\n" + - " }\n" + - " class IService {\n" + - " <>\n" + - " }\n" + - " Service *-- Dependency : IDependency\n" + - " Service *-- Dependency : IAdvancedDependency\n" + - " Composition ..> Service : IService Root"; - } - - 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(IService), 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 IService Resolve(Composition composition) - { - return composition.Root; - } - - public override IService ResolveByTag(Composition composition, object tag) - { - switch (tag) - { - case null: - return composition.Root; - default: - return base.ResolveByTag(composition, tag); - } - } - } -} -``` - -
- diff --git a/readme/property-injection.md b/readme/property-injection.md index 6c19f7aea..4f66679d3 100644 --- a/readme/property-injection.md +++ b/readme/property-injection.md @@ -16,6 +16,9 @@ interface IService class Service : IService { + // The Ordinal attribute specifies to perform an injection, + // the integer value in the argument specifies + // the ordinal of injection [Ordinal(0)] public IDependency? Dependency { get; set; } } diff --git a/readme/required-properties-or-fields.md b/readme/required-properties-or-fields.md index 2fd4645f9..2a42f90a6 100644 --- a/readme/required-properties-or-fields.md +++ b/readme/required-properties-or-fields.md @@ -22,6 +22,8 @@ class Service : IService public string Name => ServiceNameField; + // The required property will be injected automatically + // without additional effort public required IDependency Dependency { get; init; } } diff --git a/readme/resolve-methods.md b/readme/resolve-methods.md index 4466da4c2..9eb97c104 100644 --- a/readme/resolve-methods.md +++ b/readme/resolve-methods.md @@ -1,6 +1,6 @@ #### Resolve methods -[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/ResolveScenario.cs) +[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/ResolveMethodsScenario.cs) This example shows how to resolve the composition roots using the _Resolve_ methods by _Service Locator_ approach. `Resolve` methods are generated automatically for each registered root. diff --git a/readme/rootbind.md b/readme/root-binding.md similarity index 99% rename from readme/rootbind.md rename to readme/root-binding.md index 43a573957..ce7786f4a 100644 --- a/readme/rootbind.md +++ b/readme/root-binding.md @@ -1,4 +1,4 @@ -#### RootBind +#### Root binding [![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/RootBindScenario.cs) diff --git a/readme/tracking-async-disposable-instances-in-delegates.md b/readme/tracking-async-disposable-instances-in-delegates.md index dc49064f2..d095d3c5d 100644 --- a/readme/tracking-async-disposable-instances-in-delegates.md +++ b/readme/tracking-async-disposable-instances-in-delegates.md @@ -1,6 +1,6 @@ #### Tracking async disposable instances in delegates -[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/TrackingAsyncDisposableInDelegatesScenario.cs) +[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Advanced/TrackingAsyncDisposableInDelegatesScenario.cs) ```c# interface IDependency 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 6df243fae..a25bfc68f 100644 --- a/readme/tracking-async-disposable-instances-per-a-composition-root.md +++ b/readme/tracking-async-disposable-instances-per-a-composition-root.md @@ -1,6 +1,6 @@ #### Tracking async disposable instances per a composition root -[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/TrackingAsyncDisposableScenario.cs) +[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Advanced/TrackingAsyncDisposableScenario.cs) ```c# interface IDependency diff --git a/readme/tracking-disposable-instances-in-delegates.md b/readme/tracking-disposable-instances-in-delegates.md index f12fe4c62..a56f40f9d 100644 --- a/readme/tracking-disposable-instances-in-delegates.md +++ b/readme/tracking-disposable-instances-in-delegates.md @@ -1,6 +1,6 @@ #### Tracking disposable instances in delegates -[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/TrackingDisposableInDelegatesScenario.cs) +[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Advanced/TrackingDisposableInDelegatesScenario.cs) ```c# interface IDependency diff --git a/readme/tracking-disposable-instances-per-a-composition-root.md b/readme/tracking-disposable-instances-per-a-composition-root.md index 2c8edcacb..d41e8f40f 100644 --- a/readme/tracking-disposable-instances-per-a-composition-root.md +++ b/readme/tracking-disposable-instances-per-a-composition-root.md @@ -1,6 +1,6 @@ #### Tracking disposable instances per a composition root -[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Basics/TrackingDisposableScenario.cs) +[![CSharp](https://img.shields.io/badge/C%23-code-blue.svg)](../tests/Pure.DI.UsageTests/Advanced/TrackingDisposableScenario.cs) ```c# interface IDependency diff --git a/tests/Pure.DI.UsageTests/Advanced/InstanceInitializationScenario.cs b/tests/Pure.DI.UsageTests/Advanced/InstanceInitializationScenario.cs deleted file mode 100644 index b05767890..000000000 --- a/tests/Pure.DI.UsageTests/Advanced/InstanceInitializationScenario.cs +++ /dev/null @@ -1,75 +0,0 @@ -/* -$v=true -$p=2 -$d=Instance Initialization -$h=This example shows how to build up an instance with all the necessary dependencies and manually prepare it for further use. -*/ - -// ReSharper disable ClassNeverInstantiated.Local -// ReSharper disable CheckNamespace -// ReSharper disable UnusedMemberInSuper.Global -// ReSharper disable ArrangeTypeModifiers -// ReSharper disable UnusedMember.Global -namespace Pure.DI.UsageTests.Advanced.InstanceInitializationScenario; - -using Shouldly; -using Xunit; - -// { -interface IDependency; - -class Dependency : IDependency; - -interface IService -{ - string ServiceName { get; } - - IDependency Dependency { get; } - - bool IsInitialized { get; } -} - -class Service(string serviceName, IDependency dependency): IService -{ - public string ServiceName { get; } = serviceName; - - public IDependency Dependency { get; } = dependency; - - public bool IsInitialized { get; private set; } - - public void Initialize() => IsInitialized = true; -} -// } - -public class Scenario -{ - [Fact] - public void Run() - { -// { - DI.Setup(nameof(Composition)) - .Bind().To() - .Arg("serviceName") - .Bind() - .To(ctx => - { - // Builds up an instance with all necessary dependencies - ctx.Inject(out var service); - - // Executing all the necessary logic - // to prepare the instance for further use - service.Initialize(); - return service; - }) - - // Composition root - .Root("Root"); - - var composition = new Composition("My Service"); - var service = composition.Root; - service.ServiceName.ShouldBe("My Service"); - service.IsInitialized.ShouldBeTrue(); -// } - composition.SaveClassDiagram(); - } -} \ No newline at end of file diff --git a/tests/Pure.DI.UsageTests/Basics/TrackingAsyncDisposableInDelegatesScenario.cs b/tests/Pure.DI.UsageTests/Advanced/TrackingAsyncDisposableInDelegatesScenario.cs similarity index 96% rename from tests/Pure.DI.UsageTests/Basics/TrackingAsyncDisposableInDelegatesScenario.cs rename to tests/Pure.DI.UsageTests/Advanced/TrackingAsyncDisposableInDelegatesScenario.cs index e6a573354..b83419e12 100644 --- a/tests/Pure.DI.UsageTests/Basics/TrackingAsyncDisposableInDelegatesScenario.cs +++ b/tests/Pure.DI.UsageTests/Advanced/TrackingAsyncDisposableInDelegatesScenario.cs @@ -10,7 +10,7 @@ // ReSharper disable ArrangeTypeModifiers // ReSharper disable ArrangeTypeMemberModifiers // ReSharper disable UnusedMemberInSuper.Global -namespace Pure.DI.UsageTests.Basics.TrackingAsyncDisposableInDelegatesScenario; +namespace Pure.DI.UsageTests.Advanced.TrackingAsyncDisposableInDelegatesScenario; using Xunit; diff --git a/tests/Pure.DI.UsageTests/Basics/TrackingAsyncDisposableScenario.cs b/tests/Pure.DI.UsageTests/Advanced/TrackingAsyncDisposableScenario.cs similarity index 96% rename from tests/Pure.DI.UsageTests/Basics/TrackingAsyncDisposableScenario.cs rename to tests/Pure.DI.UsageTests/Advanced/TrackingAsyncDisposableScenario.cs index 3edacb7c9..ef22d1d5a 100644 --- a/tests/Pure.DI.UsageTests/Basics/TrackingAsyncDisposableScenario.cs +++ b/tests/Pure.DI.UsageTests/Advanced/TrackingAsyncDisposableScenario.cs @@ -9,7 +9,7 @@ // ReSharper disable UnusedParameterInPartialMethod // ReSharper disable ArrangeTypeModifiers // ReSharper disable ArrangeTypeMemberModifiers -namespace Pure.DI.UsageTests.Basics.TrackingAsyncDisposableScenario; +namespace Pure.DI.UsageTests.Advanced.TrackingAsyncDisposableScenario; using Xunit; diff --git a/tests/Pure.DI.UsageTests/Basics/TrackingDisposableInDelegatesScenario.cs b/tests/Pure.DI.UsageTests/Advanced/TrackingDisposableInDelegatesScenario.cs similarity index 96% rename from tests/Pure.DI.UsageTests/Basics/TrackingDisposableInDelegatesScenario.cs rename to tests/Pure.DI.UsageTests/Advanced/TrackingDisposableInDelegatesScenario.cs index f9a716a6c..78830f40e 100644 --- a/tests/Pure.DI.UsageTests/Basics/TrackingDisposableInDelegatesScenario.cs +++ b/tests/Pure.DI.UsageTests/Advanced/TrackingDisposableInDelegatesScenario.cs @@ -10,7 +10,7 @@ // ReSharper disable ArrangeTypeModifiers // ReSharper disable ArrangeTypeMemberModifiers // ReSharper disable UnusedMemberInSuper.Global -namespace Pure.DI.UsageTests.Basics.TrackingDisposableInDelegatesScenario; +namespace Pure.DI.UsageTests.Advanced.TrackingDisposableInDelegatesScenario; using Xunit; diff --git a/tests/Pure.DI.UsageTests/Basics/TrackingDisposableScenario.cs b/tests/Pure.DI.UsageTests/Advanced/TrackingDisposableScenario.cs similarity index 96% rename from tests/Pure.DI.UsageTests/Basics/TrackingDisposableScenario.cs rename to tests/Pure.DI.UsageTests/Advanced/TrackingDisposableScenario.cs index 4d4530588..155c2fd09 100644 --- a/tests/Pure.DI.UsageTests/Basics/TrackingDisposableScenario.cs +++ b/tests/Pure.DI.UsageTests/Advanced/TrackingDisposableScenario.cs @@ -9,7 +9,7 @@ // ReSharper disable UnusedParameterInPartialMethod // ReSharper disable ArrangeTypeModifiers // ReSharper disable ArrangeTypeMemberModifiers -namespace Pure.DI.UsageTests.Basics.TrackingDisposableScenario; +namespace Pure.DI.UsageTests.Advanced.TrackingDisposableScenario; using Xunit; diff --git a/tests/Pure.DI.UsageTests/Attributes/ConstructorOrdinalAttributeScenario.cs b/tests/Pure.DI.UsageTests/Attributes/ConstructorOrdinalAttributeScenario.cs index b87fbc4b6..7ab0006db 100644 --- a/tests/Pure.DI.UsageTests/Attributes/ConstructorOrdinalAttributeScenario.cs +++ b/tests/Pure.DI.UsageTests/Attributes/ConstructorOrdinalAttributeScenario.cs @@ -28,6 +28,8 @@ class Service : IService { private readonly string _name; + // The integer value in the argument specifies + // the ordinal of injection [Ordinal(1)] public Service(IDependency dependency) => _name = "with dependency"; diff --git a/tests/Pure.DI.UsageTests/Attributes/MemberOrdinalAttributeScenario.cs b/tests/Pure.DI.UsageTests/Attributes/MemberOrdinalAttributeScenario.cs index f9f9f9d6f..b40c9634c 100644 --- a/tests/Pure.DI.UsageTests/Attributes/MemberOrdinalAttributeScenario.cs +++ b/tests/Pure.DI.UsageTests/Attributes/MemberOrdinalAttributeScenario.cs @@ -28,6 +28,9 @@ class Person : IPerson public string Name => _name.ToString(); + // The Ordinal attribute specifies to perform an injection, + // the integer value in the argument specifies + // the ordinal of injection [Ordinal(0)] public int Id; diff --git a/tests/Pure.DI.UsageTests/Basics/CompositionRootsScenario.cs b/tests/Pure.DI.UsageTests/Basics/CompositionRootsScenario.cs index 5722d94bc..cdb5c6f76 100644 --- a/tests/Pure.DI.UsageTests/Basics/CompositionRootsScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/CompositionRootsScenario.cs @@ -58,18 +58,18 @@ public void Run() .Bind("Other").To() .Bind().To() - // Specifies to create a regular public composition root - // of type "IService" with the name "SomeOtherService" - // using the "Other" tag - .Root("SomeOtherService", "Other") - // Specifies to create a regular public composition root // of type "IService" with the name "MyRoot" .Root("MyRoot") // Specifies to create a private composition root // that is only accessible from "Resolve()" methods - .Root(); + .Root() + + // Specifies to create a regular public composition root + // of type "IService" with the name "SomeOtherService" + // using the "Other" tag + .Root("SomeOtherService", "Other"); var composition = new Composition(); @@ -79,6 +79,8 @@ public void Run() // someOtherService = new OtherService(); var someOtherService = composition.SomeOtherService; + // All and only the roots of the composition + // can be obtained by Resolve method var dependency = composition.Resolve(); // } service.ShouldBeOfType(); diff --git a/tests/Pure.DI.UsageTests/Basics/CompositionRootsSimplifiedScenario.cs b/tests/Pure.DI.UsageTests/Basics/CompositionRootsSimplifiedScenario.cs deleted file mode 100644 index 967884da7..000000000 --- a/tests/Pure.DI.UsageTests/Basics/CompositionRootsSimplifiedScenario.cs +++ /dev/null @@ -1,64 +0,0 @@ -/* -$v=true -$p=1 -$d=Composition roots simplified -$h=You can use `RootBind()` method in order to reduce repetitions. -*/ - -// ReSharper disable ClassNeverInstantiated.Local -// ReSharper disable CheckNamespace -// ReSharper disable UnusedParameter.Local -// ReSharper disable ArrangeTypeModifiers -// ReSharper disable ClassNeverInstantiated.Global -// ReSharper disable UnusedVariable -#pragma warning disable CS9113 // Parameter is unread. -namespace Pure.DI.UsageTests.Basics.CompositionRootsSimplifiedScenario; - -using Shouldly; -using Xunit; - -// { -interface IDependency; - -class Dependency : IDependency; - -interface IService; - -class Service(IDependency dependency) : IService; - -class OtherService : IService; -// } - -public class Scenario -{ - [Fact] - public void Run() - { -// { - DI.Setup(nameof(Composition)) - // Specifies to create a regular public composition root - // of type "IService" with the name "MyRoot" and - // it's the equivalent of statements - // .Bind().To().Root("MyRoot") - .RootBind("MyRoot").To() - - // Specifies to create a private composition root - // that is only accessible from "Resolve()" methods and - // it's the equivalent of statements - // .Bind("Other").To().Root("MyRoot") - .RootBind(tags: "Other").To() - - .Bind().To(); - - var composition = new Composition(); - - // service = new Service(new Dependency()); - var service = composition.MyRoot; - - // someOtherService = new OtherService(); - var someOtherService = composition.Resolve("Other"); -// } - service.ShouldBeOfType(); - composition.SaveClassDiagram(); - } -} \ No newline at end of file diff --git a/tests/Pure.DI.UsageTests/Basics/DefaultValuesScenario.cs b/tests/Pure.DI.UsageTests/Basics/DefaultValuesScenario.cs index da772e9db..3ef28a3a9 100644 --- a/tests/Pure.DI.UsageTests/Basics/DefaultValuesScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/DefaultValuesScenario.cs @@ -25,6 +25,8 @@ interface IService IDependency Dependency { get;} } +// If injection cannot be performed explicitly, +// the default value will be used class Service(string name = "My Service") : IService { public string Name { get; } = name; diff --git a/tests/Pure.DI.UsageTests/Basics/FactoryScenario.cs b/tests/Pure.DI.UsageTests/Basics/FactoryScenario.cs index 69bac2fe0..99a63a53c 100644 --- a/tests/Pure.DI.UsageTests/Basics/FactoryScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/FactoryScenario.cs @@ -53,8 +53,15 @@ public void Run() .Bind().To(_ => DateTimeOffset.Now) .Bind().To(ctx => { + // Some custom logic for creating an instance. + // For example, here's how you can inject + // an instance of a particular type ctx.Inject(out Dependency dependency); + + // And do something about it dependency.Initialize(); + + // And at the end return an instance return dependency; }) .Bind().To() diff --git a/tests/Pure.DI.UsageTests/Basics/FieldInjectionScenario.cs b/tests/Pure.DI.UsageTests/Basics/FieldInjectionScenario.cs index 0330bd09d..db12d15a6 100644 --- a/tests/Pure.DI.UsageTests/Basics/FieldInjectionScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/FieldInjectionScenario.cs @@ -26,6 +26,9 @@ interface IService class Service : IService { + // The Ordinal attribute specifies to perform an injection, + // the integer value in the argument specifies + // the ordinal of injection [Ordinal(0)] internal IDependency? DependencyVal; diff --git a/tests/Pure.DI.UsageTests/Basics/InjectionScenario.cs b/tests/Pure.DI.UsageTests/Basics/InjectionScenario.cs deleted file mode 100644 index 45cb478e9..000000000 --- a/tests/Pure.DI.UsageTests/Basics/InjectionScenario.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* -$v=true -$p=3 -$d=Injection -$h=This example shows how to manually create and initialize an instance by injecting the necessary dependencies. -$f=In addition to the dependency type, you can specify the dependency tag in the first parameter. Then the overloaded method `void Inject(object tag, out T value)` is used. Where the first argument is the tag, the second is the dependency instance. -*/ - -// ReSharper disable ClassNeverInstantiated.Local -// ReSharper disable CheckNamespace -// ReSharper disable UnusedVariable -// ReSharper disable UnusedMemberInSuper.Global -// ReSharper disable ArrangeTypeModifiers -// ReSharper disable UnusedMember.Global -namespace Pure.DI.UsageTests.Basics.InjectionScenario; - -using Xunit; - -// { -interface IDependency; - -class Dependency : IDependency; - -interface IService -{ - IDependency Dependency { get; } -} - -class Service(IDependency dependency) : IService -{ - public IDependency Dependency { get; } = dependency; -} -// } - -public class Scenario -{ - [Fact] - public void Run() - { -// { - DI.Setup(nameof(Composition)) - .Bind().To() - .Bind() - .To(ctx => - { - ctx.Inject(out var dependency); - return new Service(dependency); - }) - - // Composition root - .Root("Root"); - - var composition = new Composition(); - var service = composition.Root; -// } - composition.SaveClassDiagram(); - } -} \ No newline at end of file diff --git a/tests/Pure.DI.UsageTests/Basics/InjectionsOfAbstractionsScenario.cs b/tests/Pure.DI.UsageTests/Basics/InjectionsOfAbstractionsScenario.cs index a9c70b986..e2aa2ac14 100644 --- a/tests/Pure.DI.UsageTests/Basics/InjectionsOfAbstractionsScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/InjectionsOfAbstractionsScenario.cs @@ -48,7 +48,7 @@ public void Run() .Bind().To() .Bind().To() - // Specifies to create a composition root (a property) + // Specifies to create a composition root // of type "Program" with the name "Root" .Root("Root"); diff --git a/tests/Pure.DI.UsageTests/Basics/MethodInjectionScenario.cs b/tests/Pure.DI.UsageTests/Basics/MethodInjectionScenario.cs index 0c93b8693..8e8714793 100644 --- a/tests/Pure.DI.UsageTests/Basics/MethodInjectionScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/MethodInjectionScenario.cs @@ -26,6 +26,9 @@ interface IService class Service : IService { + // The Ordinal attribute specifies to perform an injection, + // the integer value in the argument specifies + // the ordinal of injection [Ordinal(0)] public void SetDependency(IDependency dependency) => Dependency = dependency; diff --git a/tests/Pure.DI.UsageTests/Basics/MultiContractBindingsScenario.cs b/tests/Pure.DI.UsageTests/Basics/MultiContractBindingsScenario.cs deleted file mode 100644 index 6085cbcac..000000000 --- a/tests/Pure.DI.UsageTests/Basics/MultiContractBindingsScenario.cs +++ /dev/null @@ -1,53 +0,0 @@ -/* -$v=true -$p=8 -$d=Multi-contract bindings -$h=An unlimited number of contracts can be attached to one implementation. Including their combinations with various tags. -*/ - -// ReSharper disable ClassNeverInstantiated.Local -// ReSharper disable CheckNamespace -// ReSharper disable UnusedParameter.Local -// ReSharper disable UnusedVariable -// ReSharper disable ArrangeTypeModifiers -#pragma warning disable CS9113 // Parameter is unread. -namespace Pure.DI.UsageTests.Basics.MultiContractBindingsScenario; - -using Xunit; - -// { -interface IDependency; - -interface IAdvancedDependency; - -class Dependency : IDependency, IAdvancedDependency; - -interface IService; - -class Service( - IDependency dependency, - IAdvancedDependency advancedDependency) - : IService; -// } - -public class Scenario -{ - [Fact] - public void Run() - { -// { - DI.Setup(nameof(Composition)) - .Bind().To() - // .Bind().Bind().To() - // is also allowed - .Bind().To() - - // Composition root - .Root("Root"); - - var composition = new Composition(); - var service = composition.Root; -// } - composition.SaveClassDiagram(); - } -} \ No newline at end of file diff --git a/tests/Pure.DI.UsageTests/Basics/PropertyInjectionScenario.cs b/tests/Pure.DI.UsageTests/Basics/PropertyInjectionScenario.cs index c51c76ac7..60ac1c94c 100644 --- a/tests/Pure.DI.UsageTests/Basics/PropertyInjectionScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/PropertyInjectionScenario.cs @@ -26,6 +26,9 @@ interface IService class Service : IService { + // The Ordinal attribute specifies to perform an injection, + // the integer value in the argument specifies + // the ordinal of injection [Ordinal(0)] public IDependency? Dependency { get; set; } } diff --git a/tests/Pure.DI.UsageTests/Basics/RequiredPropertiesOrFieldsScenario.cs b/tests/Pure.DI.UsageTests/Basics/RequiredPropertiesOrFieldsScenario.cs index 72791092a..2644e8666 100644 --- a/tests/Pure.DI.UsageTests/Basics/RequiredPropertiesOrFieldsScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/RequiredPropertiesOrFieldsScenario.cs @@ -32,6 +32,8 @@ class Service : IService public string Name => ServiceNameField; + // The required property will be injected automatically + // without additional effort public required IDependency Dependency { get; init; } } // } diff --git a/tests/Pure.DI.UsageTests/Basics/ResolveScenario.cs b/tests/Pure.DI.UsageTests/Basics/ResolveMethodsScenario.cs similarity index 97% rename from tests/Pure.DI.UsageTests/Basics/ResolveScenario.cs rename to tests/Pure.DI.UsageTests/Basics/ResolveMethodsScenario.cs index 61dd95d8d..15752d53a 100644 --- a/tests/Pure.DI.UsageTests/Basics/ResolveScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/ResolveMethodsScenario.cs @@ -11,7 +11,7 @@ // ReSharper disable ArrangeTypeModifiers // ReSharper disable UnusedVariable #pragma warning disable CS9113 // Parameter is unread. -namespace Pure.DI.UsageTests.Basics.ResolveScenario; +namespace Pure.DI.UsageTests.Basics.ResolveMethodsScenario; using Shouldly; using Xunit; diff --git a/tests/Pure.DI.UsageTests/Basics/RootBindScenario.cs b/tests/Pure.DI.UsageTests/Basics/RootBindScenario.cs index 418d3aa19..a16041c39 100644 --- a/tests/Pure.DI.UsageTests/Basics/RootBindScenario.cs +++ b/tests/Pure.DI.UsageTests/Basics/RootBindScenario.cs @@ -1,7 +1,7 @@ /* $v=true $p=17 -$d=RootBind +$d=Root binding $h=You might want to register some services as roots. You can use `RootBind()` method in order to reduce repetitions. The registration `composition.RootBind().To()` is an equivalent to `composition.Bind().To().Root()`. */ diff --git a/tests/Pure.DI.UsageTests/Lifetimes/DefaultLifetimeScenario.cs b/tests/Pure.DI.UsageTests/Lifetimes/DefaultLifetimeScenario.cs index cc9b395be..b6dd82610 100644 --- a/tests/Pure.DI.UsageTests/Lifetimes/DefaultLifetimeScenario.cs +++ b/tests/Pure.DI.UsageTests/Lifetimes/DefaultLifetimeScenario.cs @@ -42,7 +42,11 @@ public void Run() { // { DI.Setup(nameof(Composition)) + // Default Lifetime applies + // to all bindings until the end of the chain + // or the next call to the DefaultLifetime method .DefaultLifetime(Lifetime.Singleton) + .Bind().To() .RootBind("Root").To();