From 02118080d8ece7756e76daa7bbd4b44a5f6eee35 Mon Sep 17 00:00:00 2001 From: hadashi Date: Sat, 1 May 2021 19:47:08 +0900 Subject: [PATCH 1/6] Make sure to separate the RegisterInstance feature from the default Registration --- .../VContainer/Runtime/ContainerBuilder.cs | 5 +-- .../Runtime/ContainerBuilderExtensions.cs | 11 +---- .../Runtime/InstanceRegistrationBuilder.cs | 28 ++++++++++++ .../InstanceRegistrationBuilder.cs.meta | 3 ++ .../Runtime/Internal/InstanceRegistration.cs | 45 +++++++++++++++++++ .../Internal/InstanceRegistration.cs.meta | 3 ++ .../Runtime/Internal/Registration.cs | 15 +------ .../VContainer/Runtime/RegistrationBuilder.cs | 14 +----- .../Unity/ComponentRegistrationBuilder.cs | 23 ++++------ .../Assets/VContainer/Tests/ContainerTest.cs | 16 +++---- 10 files changed, 100 insertions(+), 63 deletions(-) create mode 100644 VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs create mode 100644 VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs.meta create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs.meta diff --git a/VContainer/Assets/VContainer/Runtime/ContainerBuilder.cs b/VContainer/Assets/VContainer/Runtime/ContainerBuilder.cs index 731611c1..3f81aa8e 100644 --- a/VContainer/Assets/VContainer/Runtime/ContainerBuilder.cs +++ b/VContainer/Assets/VContainer/Runtime/ContainerBuilder.cs @@ -12,8 +12,8 @@ public interface IContainerBuilder object ApplicationOrigin { get; set; } RegistrationBuilder Register(Type type, Lifetime lifetime); - RegistrationBuilder RegisterInstance(object instance); RegistrationBuilder Register(RegistrationBuilder registrationBuilder); + void RegisterBuildCallback(Action container); bool Exists(Type type, bool includeInterfaceTypes = false); @@ -52,9 +52,6 @@ public class ContainerBuilder : IContainerBuilder public RegistrationBuilder Register(Type type, Lifetime lifetime) => Register(new RegistrationBuilder(type, lifetime)); - public RegistrationBuilder RegisterInstance(object instance) - => Register(new RegistrationBuilder(instance)); - public RegistrationBuilder Register(RegistrationBuilder registrationBuilder) { registrationBuilders.Add(registrationBuilder); diff --git a/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs b/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs index 62cf0b13..6501b96f 100644 --- a/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs +++ b/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs @@ -31,16 +31,7 @@ public static RegistrationBuilder Register( this IContainerBuilder builder, TInterface instance) - => builder.RegisterInstance(instance).As(typeof(TInterface)); - - public static RegistrationBuilder RegisterInstance( - this IContainerBuilder builder, - object instance) - => builder.RegisterInstance(instance).As(typeof(TInterface1), typeof(TInterface2)); - - public static RegistrationBuilder RegisterInstance( - this IContainerBuilder builder, object instance) - => builder.RegisterInstance(instance).As(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3)); + => builder.Register(new InstanceRegistrationBuilder(instance)).As(typeof(TInterface)); public static RegistrationBuilder RegisterFactory( this IContainerBuilder builder, diff --git a/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs b/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs new file mode 100644 index 00000000..2236297a --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs @@ -0,0 +1,28 @@ +using VContainer.Internal; + +namespace VContainer +{ + public sealed class InstanceRegistrationBuilder : RegistrationBuilder + { + readonly object instance; + + public InstanceRegistrationBuilder(object instance) + : base(instance.GetType(), Lifetime.Singleton) + { + this.instance = instance; + } + + public override IRegistration Build() + { + var injector = InjectorCache.GetOrBuild(ImplementationType); + + return new InstanceRegistration( + instance, + ImplementationType, + Lifetime, + InterfaceTypes, + Parameters, + injector); + } + } +} \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs.meta b/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs.meta new file mode 100644 index 00000000..72123ca3 --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 097b02c25ccf47df97386afb6a4f0c21 +timeCreated: 1619863604 \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs b/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs new file mode 100644 index 00000000..62bcba88 --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +namespace VContainer.Internal +{ + sealed class InstanceRegistration : IRegistration + { + public Type ImplementationType { get; } + public IReadOnlyList InterfaceTypes { get; } + public Lifetime Lifetime { get; } + + readonly object instance; + readonly IInjector injector; + readonly IReadOnlyList parameters; + + long injected; + + public InstanceRegistration( + object instance, + Type implementationType, + Lifetime lifetime, + IReadOnlyList interfaceTypes, + IReadOnlyList parameters, + IInjector injector) + { + ImplementationType = implementationType; + Lifetime = lifetime; + InterfaceTypes = interfaceTypes; + + this.instance = instance; + this.injector = injector; + this.parameters = parameters; + } + + public object SpawnInstance(IObjectResolver resolver) + { + if (Interlocked.CompareExchange(ref injected, 1, 0) == 0) + { + injector.Inject(instance, resolver, parameters); + } + return instance; + } + } +} \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs.meta b/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs.meta new file mode 100644 index 00000000..2b2de677 --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4fcef74c11fc4018bbc88bc395ef8657 +timeCreated: 1619863673 \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/Registration.cs b/VContainer/Assets/VContainer/Runtime/Internal/Registration.cs index 0585603e..5441af0c 100644 --- a/VContainer/Assets/VContainer/Runtime/Internal/Registration.cs +++ b/VContainer/Assets/VContainer/Runtime/Internal/Registration.cs @@ -11,38 +11,27 @@ sealed class Registration : IRegistration public Lifetime Lifetime { get; } readonly IInjector injector; - readonly IReadOnlyList parameters; - readonly object specificInstance; internal Registration( Type implementationType, Lifetime lifetime, IReadOnlyList interfaceTypes, IReadOnlyList parameters, - IInjector injector, - object specificInstance) + IInjector injector) { ImplementationType = implementationType; InterfaceTypes = interfaceTypes; Lifetime = lifetime; this.injector = injector; - this.specificInstance = specificInstance; this.parameters = parameters; } public override string ToString() => $"ConcreteType={ImplementationType.Name} ContractTypes={string.Join(", ", InterfaceTypes)} {Lifetime} {injector.GetType().Name}"; public object SpawnInstance(IObjectResolver resolver) - { - if (specificInstance != null) - { - injector.Inject(specificInstance, resolver, parameters); - return specificInstance; - } - return injector.CreateInstance(resolver, parameters); - } + => injector.CreateInstance(resolver, parameters); } sealed class CollectionRegistration : IRegistration, IEnumerable diff --git a/VContainer/Assets/VContainer/Runtime/RegistrationBuilder.cs b/VContainer/Assets/VContainer/Runtime/RegistrationBuilder.cs index 658bce6f..dce68d87 100644 --- a/VContainer/Assets/VContainer/Runtime/RegistrationBuilder.cs +++ b/VContainer/Assets/VContainer/Runtime/RegistrationBuilder.cs @@ -10,25 +10,16 @@ public class RegistrationBuilder internal readonly Type ImplementationType; internal readonly Lifetime Lifetime; - internal readonly object SpecificInstance; internal List InterfaceTypes; internal List Parameters; - public RegistrationBuilder(Type implementationType, Lifetime lifetime, List interfaceTypes = null) + public RegistrationBuilder(Type implementationType, Lifetime lifetime) { ImplementationType = implementationType; - InterfaceTypes = interfaceTypes; Lifetime = lifetime; } - public RegistrationBuilder(object instance) - { - ImplementationType = instance.GetType(); - Lifetime = Lifetime.Singleton; - SpecificInstance = instance; - } - public virtual IRegistration Build() { var injector = InjectorCache.GetOrBuild(ImplementationType); @@ -38,8 +29,7 @@ public virtual IRegistration Build() Lifetime, InterfaceTypes, Parameters, - injector, - SpecificInstance); + injector); } public RegistrationBuilder As() diff --git a/VContainer/Assets/VContainer/Runtime/Unity/ComponentRegistrationBuilder.cs b/VContainer/Assets/VContainer/Runtime/Unity/ComponentRegistrationBuilder.cs index 072d6f15..9524ec47 100644 --- a/VContainer/Assets/VContainer/Runtime/Unity/ComponentRegistrationBuilder.cs +++ b/VContainer/Assets/VContainer/Runtime/Unity/ComponentRegistrationBuilder.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using VContainer.Internal; @@ -19,9 +18,8 @@ public sealed class ComponentRegistrationBuilder : RegistrationBuilder internal ComponentRegistrationBuilder( Component prefab, Type implementationType, - Lifetime lifetime, - List interfaceTypes = null) - : this(false, default, implementationType, lifetime, interfaceTypes) + Lifetime lifetime) + : this(false, default, implementationType, lifetime) { this.prefab = prefab; } @@ -29,18 +27,14 @@ internal ComponentRegistrationBuilder( internal ComponentRegistrationBuilder( string gameObjectName, Type implementationType, - Lifetime lifetime, - List interfaceTypes = null) - : this(false, default, implementationType, lifetime, interfaceTypes) + Lifetime lifetime) + : this(false, default, implementationType, lifetime) { this.gameObjectName = gameObjectName; } - internal ComponentRegistrationBuilder( - Scene scene, - Type implementationType, - List interfaceTypes = null) - : this(true, scene, implementationType, Lifetime.Scoped, interfaceTypes) + internal ComponentRegistrationBuilder(Scene scene, Type implementationType) + : this(true, scene, implementationType, Lifetime.Scoped) { } @@ -48,9 +42,8 @@ internal ComponentRegistrationBuilder( bool find, Scene scene, Type implementationType, - Lifetime lifetime, - List interfaceTypes = null) - : base(implementationType, lifetime, interfaceTypes) + Lifetime lifetime) + : base(implementationType, lifetime) { this.find = find; this.scene = scene; diff --git a/VContainer/Assets/VContainer/Tests/ContainerTest.cs b/VContainer/Assets/VContainer/Tests/ContainerTest.cs index 1fec11d2..ecc73ff1 100644 --- a/VContainer/Assets/VContainer/Tests/ContainerTest.cs +++ b/VContainer/Assets/VContainer/Tests/ContainerTest.cs @@ -252,22 +252,20 @@ public void RegisterInstance() var builder = new ContainerBuilder(); var instance1 = new NoDependencyServiceB(); var instance2 = new MultipleInterfaceServiceA(); - builder.RegisterInstance(instance1); - builder.RegisterInstance(instance2); + builder.RegisterInstance(instance1); + builder.RegisterInstance(instance2); var container = builder.Build(); - var resolve1a = container.Resolve(); - var resolve1b = container.Resolve(); + var resolve1a = container.Resolve(); + var resolve1b = container.Resolve(); + var resolve2a = container.Resolve(); + var resolve2b = container.Resolve(); Assert.That(resolve1a, Is.EqualTo(instance1)); Assert.That(resolve1b, Is.EqualTo(instance1)); - Assert.Throws(() => container.Resolve()); - - var resolve2a = container.Resolve(); - var resolve2b = container.Resolve(); Assert.That(resolve2a, Is.EqualTo(instance2)); Assert.That(resolve2b, Is.EqualTo(instance2)); - Assert.Throws(() => container.Resolve()); + Assert.Throws(() => container.Resolve()); } [Test] From 25254f5a235d0d7c2f5d9d279507d03e58fcf8ce Mon Sep 17 00:00:00 2001 From: hadashi Date: Sat, 1 May 2021 20:46:16 +0900 Subject: [PATCH 2/6] Make InstanceRegistration internal --- .../Runtime/ContainerBuilderExtensions.cs | 17 +++++++++++ .../Runtime/InstanceRegistrationBuilder.cs | 28 ------------------- .../Runtime/Internal/InstanceRegistration.cs | 10 +++---- .../Internal/InstanceRegistrationBuilder.cs | 26 +++++++++++++++++ .../InstanceRegistrationBuilder.cs.meta | 0 5 files changed, 48 insertions(+), 33 deletions(-) delete mode 100644 VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistrationBuilder.cs rename VContainer/Assets/VContainer/Runtime/{ => Internal}/InstanceRegistrationBuilder.cs.meta (100%) diff --git a/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs b/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs index 6501b96f..574c9985 100644 --- a/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs +++ b/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs @@ -28,11 +28,28 @@ public static RegistrationBuilder Register builder.Register(lifetime).As(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3)); + public static RegistrationBuilder Register( + this IContainerBuilder builder, + Func implementationConfiguration, + Lifetime lifetime) + where TInterface : class + => builder.Register(new FuncRegistrationBuilder(implementationConfiguration, typeof(TInterface), lifetime)); + public static RegistrationBuilder RegisterInstance( this IContainerBuilder builder, TInterface instance) => builder.Register(new InstanceRegistrationBuilder(instance)).As(typeof(TInterface)); + public static RegistrationBuilder RegisterInstance( + this IContainerBuilder builder, + TInterface1 instance) + => builder.RegisterInstance(instance).As(typeof(TInterface1), typeof(TInterface2)); + + public static RegistrationBuilder RegisterInstance( + this IContainerBuilder builder, + TInterface1 instance) + => builder.RegisterInstance(instance).As(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3)); + public static RegistrationBuilder RegisterFactory( this IContainerBuilder builder, Func factory) diff --git a/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs b/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs deleted file mode 100644 index 2236297a..00000000 --- a/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs +++ /dev/null @@ -1,28 +0,0 @@ -using VContainer.Internal; - -namespace VContainer -{ - public sealed class InstanceRegistrationBuilder : RegistrationBuilder - { - readonly object instance; - - public InstanceRegistrationBuilder(object instance) - : base(instance.GetType(), Lifetime.Singleton) - { - this.instance = instance; - } - - public override IRegistration Build() - { - var injector = InjectorCache.GetOrBuild(ImplementationType); - - return new InstanceRegistration( - instance, - ImplementationType, - Lifetime, - InterfaceTypes, - Parameters, - injector); - } - } -} \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs b/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs index 62bcba88..79d8e0fa 100644 --- a/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs +++ b/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistration.cs @@ -10,14 +10,14 @@ sealed class InstanceRegistration : IRegistration public IReadOnlyList InterfaceTypes { get; } public Lifetime Lifetime { get; } - readonly object instance; + readonly object implementationInstance; readonly IInjector injector; readonly IReadOnlyList parameters; long injected; public InstanceRegistration( - object instance, + object implementationInstance, Type implementationType, Lifetime lifetime, IReadOnlyList interfaceTypes, @@ -28,7 +28,7 @@ public InstanceRegistration( Lifetime = lifetime; InterfaceTypes = interfaceTypes; - this.instance = instance; + this.implementationInstance = implementationInstance; this.injector = injector; this.parameters = parameters; } @@ -37,9 +37,9 @@ public object SpawnInstance(IObjectResolver resolver) { if (Interlocked.CompareExchange(ref injected, 1, 0) == 0) { - injector.Inject(instance, resolver, parameters); + injector.Inject(implementationInstance, resolver, parameters); } - return instance; + return implementationInstance; } } } \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistrationBuilder.cs b/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistrationBuilder.cs new file mode 100644 index 00000000..8ecd51a2 --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistrationBuilder.cs @@ -0,0 +1,26 @@ +namespace VContainer.Internal +{ + sealed class InstanceRegistrationBuilder : RegistrationBuilder + { + readonly object implementationInstance; + + public InstanceRegistrationBuilder(object implementationInstance) + : base(implementationInstance.GetType(), Lifetime.Singleton) + { + this.implementationInstance = implementationInstance; + } + + public override IRegistration Build() + { + var injector = InjectorCache.GetOrBuild(ImplementationType); + + return new InstanceRegistration( + implementationInstance, + ImplementationType, + Lifetime, + InterfaceTypes, + Parameters, + injector); + } + } +} \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs.meta b/VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistrationBuilder.cs.meta similarity index 100% rename from VContainer/Assets/VContainer/Runtime/InstanceRegistrationBuilder.cs.meta rename to VContainer/Assets/VContainer/Runtime/Internal/InstanceRegistrationBuilder.cs.meta From 8ba1767d51179d9385f5299e625ac3e39169cf35 Mon Sep 17 00:00:00 2001 From: hadashi Date: Sat, 1 May 2021 20:47:08 +0900 Subject: [PATCH 3/6] Add Register(Func<,>) style api --- .../Runtime/Internal/FuncRegistration.cs | 29 +++++++++++ .../Runtime/Internal/FuncRegistration.cs.meta | 3 ++ .../Internal/FuncRegistrationBuilder.cs | 23 ++++++++ .../Internal/FuncRegistrationBuilder.cs.meta | 3 ++ .../Assets/VContainer/Tests/ContainerTest.cs | 52 +++++++++++++++++++ 5 files changed, 110 insertions(+) create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/FuncRegistration.cs create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/FuncRegistration.cs.meta create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilder.cs create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilder.cs.meta diff --git a/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistration.cs b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistration.cs new file mode 100644 index 00000000..905f2c0f --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistration.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; + +namespace VContainer.Internal +{ + sealed class FuncRegistration : IRegistration + { + public Type ImplementationType { get; } + public IReadOnlyList InterfaceTypes { get; } + public Lifetime Lifetime { get; } + + readonly Func implementationProvider; + + public FuncRegistration( + Func implementationProvider, + Type implementationType, + Lifetime lifetime, + IReadOnlyList interfaceTypes) + { + ImplementationType = implementationType; + Lifetime = lifetime; + InterfaceTypes = interfaceTypes; + + this.implementationProvider = implementationProvider; + } + + public object SpawnInstance(IObjectResolver resolver) => implementationProvider(resolver); + } +} \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistration.cs.meta b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistration.cs.meta new file mode 100644 index 00000000..fbc5870f --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistration.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a4fb0cd9294e424bb69b28711f95ccc0 +timeCreated: 1619867067 \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilder.cs b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilder.cs new file mode 100644 index 00000000..90c6c27d --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilder.cs @@ -0,0 +1,23 @@ +using System; + +namespace VContainer.Internal +{ + sealed class FuncRegistrationBuilder : RegistrationBuilder + { + readonly Func implementationConfiguration; + + public FuncRegistrationBuilder( + Func implementationConfiguration, + Type implementationType, + Lifetime lifetime) : base(implementationType, lifetime) + { + this.implementationConfiguration = implementationConfiguration; + } + + public override IRegistration Build() => new FuncRegistration( + implementationConfiguration, + ImplementationType, + Lifetime, + InterfaceTypes); + } +} diff --git a/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilder.cs.meta b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilder.cs.meta new file mode 100644 index 00000000..4267c4ee --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 959eabb8a5cb4f198c7e96512ea177b8 +timeCreated: 1619866780 \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Tests/ContainerTest.cs b/VContainer/Assets/VContainer/Tests/ContainerTest.cs index ecc73ff1..c94fbd73 100644 --- a/VContainer/Assets/VContainer/Tests/ContainerTest.cs +++ b/VContainer/Assets/VContainer/Tests/ContainerTest.cs @@ -279,6 +279,58 @@ public void RegisterInstanceWithEnum() Assert.That(enumResolved, Is.EqualTo(Lifetime.Scoped)); } + [Test] + public void RegisterFromFunc() + { + var builder = new ContainerBuilder(); + builder.Register(Lifetime.Transient); + + builder.Register(container => + { + return new ServiceA(container.Resolve()); + }, Lifetime.Scoped); + + var container = builder.Build(); + var resolved = container.Resolve(); + Assert.That(resolved, Is.InstanceOf()); + Assert.That(resolved.Service2, Is.InstanceOf()); + } + + [Test] + public void RegisterFromFuncWithInterface() + { + var builder = new ContainerBuilder(); + builder.Register(Lifetime.Transient); + + builder.Register(container => + { + return new ServiceA(container.Resolve()); + }, Lifetime.Scoped); + + var container = builder.Build(); + var resolved = container.Resolve(); + Assert.That(resolved, Is.InstanceOf()); + Assert.Throws(() => container.Resolve()); + } + + [Test] + public void RegisterFromFuncWithDisposable() + { + var builder = new ContainerBuilder(); + builder.Register(container => + { + return new DisposableServiceA(); + }, Lifetime.Scoped); + + var container = builder.Build(); + var resolved = container.Resolve(); + Assert.That(resolved, Is.InstanceOf()); + Assert.That(resolved.Disposed, Is.False); + + container.Dispose(); + Assert.That(resolved.Disposed, Is.True); + } + [Test] public void RegisterMultipleDisposables() { From f01c019f92e85959e00cd0c824324da948286dcb Mon Sep 17 00:00:00 2001 From: hadashi Date: Sat, 1 May 2021 21:17:36 +0900 Subject: [PATCH 4/6] [docs] Add Register(Func<,>) style api --- website/docs/registering/register-type.mdx | 47 +++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/website/docs/registering/register-type.mdx b/website/docs/registering/register-type.mdx index 158bebd0..c89f3d03 100644 --- a/website/docs/registering/register-type.mdx +++ b/website/docs/registering/register-type.mdx @@ -115,7 +115,7 @@ class GameController : IStartable, ITickable, IDisposable { /* ... */ } ``` ```csharp -builder.RegisterEntryPoint(Lifetime.Singleton); +builder.RegisterEntryPoint(); ``` :::note @@ -192,6 +192,51 @@ builder.RegisterInstance() .AsImplementedInterfaces(); ``` +## Register instance to set up from delegate + +Instance creation can be delegated to a lambda expression or another method or class. + +```csharp +builder.Register(_ => new Foo(), Lifetime.Scoped); +``` + +It can resolve like this: + +```csharp +class ClassA +{ + public ClassA(IFoo foo) { /* ...*/ } +} +``` + +The first argument that can be used in the expression is `IObjectResolver`. +Using this, we can retrieve and use the registered object. + +```csharp +builder.Register(container => +{ + var serviceA = container.Resolve(); + return serviceA.ProvideFoo(); +}, Lifetime.Scoped); +``` + +`IObjectResolver.Instantiate` can also be used to generate GameObjects executed inject. + +```csharp +builder.Register(container => +{ + return container.Instantiate(prefab); +}, Lifetime.Scoped); + +``` +See [Use Container directory](../container-api/use-container-directory) more information. + +:::note +These delegates will be executed only once during scope construction. +If you want to create an instance at any time during runtime, please refer to [Register Factory](./register-factory). +::: + + ## Register type-specific parameters If the types are not unique, but you have a dependency you want to inject at startup, you can use the following: From a7f44e18c752cd5d43cb09c62277ba6fd095b152 Mon Sep 17 00:00:00 2001 From: hadashi Date: Sat, 1 May 2021 21:47:23 +0900 Subject: [PATCH 5/6] Fix compilation errors for unity 2019 --- VContainer/Assets/VContainer/Tests/ContainerTest.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/VContainer/Assets/VContainer/Tests/ContainerTest.cs b/VContainer/Assets/VContainer/Tests/ContainerTest.cs index c94fbd73..9fece785 100644 --- a/VContainer/Assets/VContainer/Tests/ContainerTest.cs +++ b/VContainer/Assets/VContainer/Tests/ContainerTest.cs @@ -285,9 +285,9 @@ public void RegisterFromFunc() var builder = new ContainerBuilder(); builder.Register(Lifetime.Transient); - builder.Register(container => + builder.Register(c => { - return new ServiceA(container.Resolve()); + return new ServiceA(c.Resolve()); }, Lifetime.Scoped); var container = builder.Build(); @@ -302,9 +302,9 @@ public void RegisterFromFuncWithInterface() var builder = new ContainerBuilder(); builder.Register(Lifetime.Transient); - builder.Register(container => + builder.Register(c => { - return new ServiceA(container.Resolve()); + return new ServiceA(c.Resolve()); }, Lifetime.Scoped); var container = builder.Build(); @@ -317,7 +317,7 @@ public void RegisterFromFuncWithInterface() public void RegisterFromFuncWithDisposable() { var builder = new ContainerBuilder(); - builder.Register(container => + builder.Register(_ => { return new DisposableServiceA(); }, Lifetime.Scoped); From 654580c62474fe2687e0a6e57cf0a91fe16b0936 Mon Sep 17 00:00:00 2001 From: hadashi Date: Sat, 1 May 2021 21:59:53 +0900 Subject: [PATCH 6/6] Fix compilation errors for ecs integration --- .../Runtime/Unity/SystemRegistrationBuilder.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/VContainer/Assets/VContainer/Runtime/Unity/SystemRegistrationBuilder.cs b/VContainer/Assets/VContainer/Runtime/Unity/SystemRegistrationBuilder.cs index e23f1654..798339da 100644 --- a/VContainer/Assets/VContainer/Runtime/Unity/SystemRegistrationBuilder.cs +++ b/VContainer/Assets/VContainer/Runtime/Unity/SystemRegistrationBuilder.cs @@ -11,16 +11,15 @@ public sealed class SystemRegistrationBuilder : RegistrationBuilder readonly string worldName; Type systemGroupType; - internal SystemRegistrationBuilder( - Type implementationType, - string worldName, - List interfaceTypes = null) - : base(implementationType, default, interfaceTypes) + internal SystemRegistrationBuilder(Type implementationType, string worldName) + : base(implementationType, default) { this.worldName = worldName; - InterfaceTypes = InterfaceTypes ?? new List(); - InterfaceTypes.Add(typeof(ComponentSystemBase)); - InterfaceTypes.Add(ImplementationType); + InterfaceTypes = new List + { + typeof(ComponentSystemBase), + implementationType + }; } public override IRegistration Build()