From 8ee16c9d1b1ca5d1dc50c9cbc33aa5734d907b45 Mon Sep 17 00:00:00 2001 From: Alon Talmi Date: Tue, 14 Nov 2023 11:12:32 +0100 Subject: [PATCH 1/3] InstanceProviderCallbackDecorator InstanceProviderCallbackDecorator.meta --- .../InstanceProviderCallbackDecorator.cs | 23 +++++++++++++++++++ .../InstanceProviderCallbackDecorator.cs.meta | 11 +++++++++ 2 files changed, 34 insertions(+) create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/InstanceProviders/InstanceProviderCallbackDecorator.cs create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/InstanceProviders/InstanceProviderCallbackDecorator.cs.meta diff --git a/VContainer/Assets/VContainer/Runtime/Internal/InstanceProviders/InstanceProviderCallbackDecorator.cs b/VContainer/Assets/VContainer/Runtime/Internal/InstanceProviders/InstanceProviderCallbackDecorator.cs new file mode 100644 index 00000000..8f1d3329 --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/InstanceProviders/InstanceProviderCallbackDecorator.cs @@ -0,0 +1,23 @@ +using System; + +namespace VContainer.Internal +{ + sealed class InstanceProviderCallbackDecorator : IInstanceProvider + { + readonly Action callback; + readonly IInstanceProvider instanceProvider; + + public InstanceProviderCallbackDecorator(IInstanceProvider instanceProvider, Action callback) + { + this.instanceProvider = instanceProvider; + this.callback = callback; + } + + public object SpawnInstance(IObjectResolver resolver) + { + var instance = instanceProvider.SpawnInstance(resolver); + callback(instance, resolver); + return instance; + } + } +} \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/InstanceProviders/InstanceProviderCallbackDecorator.cs.meta b/VContainer/Assets/VContainer/Runtime/Internal/InstanceProviders/InstanceProviderCallbackDecorator.cs.meta new file mode 100644 index 00000000..18b915aa --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/InstanceProviders/InstanceProviderCallbackDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86cc7bf9124054c378bd7cbce955f9f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 7f2fbbade84569282c8027cfe79f212d97f24b54 Mon Sep 17 00:00:00 2001 From: Alon Talmi Date: Tue, 14 Nov 2023 13:06:21 +0100 Subject: [PATCH 2/3] RegistrationBuilder variations with callback Meta files --- .../Runtime/ContainerBuilderExtensions.cs | 48 +++++++++++++++++++ .../FuncRegistrationBuilderWithCallback.cs | 26 ++++++++++ ...uncRegistrationBuilderWithCallback.cs.meta | 11 +++++ .../RegistrationBuilderWithCallback.cs | 26 ++++++++++ .../RegistrationBuilderWithCallback.cs.meta | 11 +++++ 5 files changed, 122 insertions(+) create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilderWithCallback.cs create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilderWithCallback.cs.meta create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/RegistrationBuilderWithCallback.cs create mode 100644 VContainer/Assets/VContainer/Runtime/Internal/RegistrationBuilderWithCallback.cs.meta diff --git a/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs b/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs index f653cceb..a9156702 100644 --- a/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs +++ b/VContainer/Assets/VContainer/Runtime/ContainerBuilderExtensions.cs @@ -12,12 +12,27 @@ public static RegistrationBuilder Register( Type type, Lifetime lifetime) => builder.Register(new RegistrationBuilder(type, lifetime)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RegistrationBuilder Register( + this IContainerBuilder builder, + Type type, + Lifetime lifetime, + Action callback) + => builder.Register(new RegistrationBuilderWithCallback(type, lifetime, callback)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static RegistrationBuilder Register( this IContainerBuilder builder, Lifetime lifetime) => builder.Register(typeof(T), lifetime); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RegistrationBuilder Register( + this IContainerBuilder builder, + Lifetime lifetime, + Action callback) + => builder.Register(typeof(T), lifetime, (instance, resolver) => callback((T)instance, resolver)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static RegistrationBuilder Register( @@ -25,6 +40,14 @@ public static RegistrationBuilder Register( Lifetime lifetime) where TImplement : TInterface => builder.Register(lifetime).As(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RegistrationBuilder Register( + this IContainerBuilder builder, + Lifetime lifetime, + Action callback) + where TImplement : TInterface + => builder.Register(lifetime, callback).As(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static RegistrationBuilder Register( @@ -32,6 +55,14 @@ public static RegistrationBuilder Register Lifetime lifetime) where TImplement : TInterface1, TInterface2 => builder.Register(lifetime).As(typeof(TInterface1), typeof(TInterface2)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RegistrationBuilder Register( + this IContainerBuilder builder, + Lifetime lifetime, + Action callback) + where TImplement : TInterface1, TInterface2 + => builder.Register(lifetime, callback).As(typeof(TInterface1), typeof(TInterface2)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static RegistrationBuilder Register( @@ -39,6 +70,14 @@ public static RegistrationBuilder Register builder.Register(lifetime).As(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RegistrationBuilder Register( + this IContainerBuilder builder, + Lifetime lifetime, + Action callback) + where TImplement : TInterface1, TInterface2, TInterface3 + => builder.Register(lifetime, callback).As(typeof(TInterface1), typeof(TInterface2), typeof(TInterface3)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static RegistrationBuilder Register( @@ -47,6 +86,15 @@ public static RegistrationBuilder Register( Lifetime lifetime) where TInterface : class => builder.Register(new FuncRegistrationBuilder(implementationConfiguration, typeof(TInterface), lifetime)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RegistrationBuilder Register( + this IContainerBuilder builder, + Func implementationConfiguration, + Lifetime lifetime, + Action callback) + where TInterface : class + => builder.Register(new FuncRegistrationBuilderWithCallback(implementationConfiguration, typeof(TInterface), lifetime, (instance, resolver) => callback((TInterface)instance, resolver))); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static RegistrationBuilder RegisterInstance( diff --git a/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilderWithCallback.cs b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilderWithCallback.cs new file mode 100644 index 00000000..50a6b525 --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilderWithCallback.cs @@ -0,0 +1,26 @@ +using System; + +namespace VContainer.Internal +{ + sealed class FuncRegistrationBuilderWithCallback : RegistrationBuilder + { + readonly Func implementationProvider; + readonly Action callback; + + public FuncRegistrationBuilderWithCallback( + Func implementationProvider, + Type implementationType, + Lifetime lifetime, + Action callback) : base(implementationType, lifetime) + { + this.implementationProvider = implementationProvider; + this.callback = callback; + } + + public override Registration Build() + { + var spawner = new InstanceProviderCallbackDecorator(new FuncInstanceProvider(implementationProvider), callback); + return new Registration(ImplementationType, Lifetime, InterfaceTypes, spawner); + } + } +} \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilderWithCallback.cs.meta b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilderWithCallback.cs.meta new file mode 100644 index 00000000..3a6dcaaa --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/FuncRegistrationBuilderWithCallback.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 14af63c391fa747d7aee3aa839177cd3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VContainer/Assets/VContainer/Runtime/Internal/RegistrationBuilderWithCallback.cs b/VContainer/Assets/VContainer/Runtime/Internal/RegistrationBuilderWithCallback.cs new file mode 100644 index 00000000..5ff562cb --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/RegistrationBuilderWithCallback.cs @@ -0,0 +1,26 @@ +using System; + +namespace VContainer.Internal +{ + sealed class RegistrationBuilderWithCallback : RegistrationBuilder + { + readonly Action callback; + + public RegistrationBuilderWithCallback(Type implementationType, Lifetime lifetime, Action callback) + : base(implementationType, lifetime) + { + this.callback = callback; + } + + public override Registration Build() + { + var injector = InjectorCache.GetOrBuild(ImplementationType); + var spawner = new InstanceProviderCallbackDecorator(new InstanceProvider(injector, Parameters), callback); + return new Registration( + ImplementationType, + Lifetime, + InterfaceTypes, + spawner); + } + } +} \ No newline at end of file diff --git a/VContainer/Assets/VContainer/Runtime/Internal/RegistrationBuilderWithCallback.cs.meta b/VContainer/Assets/VContainer/Runtime/Internal/RegistrationBuilderWithCallback.cs.meta new file mode 100644 index 00000000..be07974a --- /dev/null +++ b/VContainer/Assets/VContainer/Runtime/Internal/RegistrationBuilderWithCallback.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5fc07c6224ff400881f83cdbd896711 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From fa6361ae4e087fdfd9a9bec248116eef64dcb677 Mon Sep 17 00:00:00 2001 From: Alon Talmi Date: Wed, 15 Nov 2023 08:29:49 +0100 Subject: [PATCH 3/3] Added resolve callback Unit Tests --- .../Assets/VContainer/Tests/ContainerTest.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/VContainer/Assets/VContainer/Tests/ContainerTest.cs b/VContainer/Assets/VContainer/Tests/ContainerTest.cs index 3924b52d..174a1f05 100644 --- a/VContainer/Assets/VContainer/Tests/ContainerTest.cs +++ b/VContainer/Assets/VContainer/Tests/ContainerTest.cs @@ -518,5 +518,35 @@ public void Inject() var ctorInjectable = new ServiceA(new NoDependencyServiceA()); Assert.DoesNotThrow(() => container.Inject(ctorInjectable)); } + + [Test] + public void RegisterWithCallback() + { + { + NoDependencyServiceA fromCallback = null; + + var builder = new ContainerBuilder(); + builder.Register(Lifetime.Scoped, (service, _) => fromCallback = service); + + var container = builder.Build(); + + var fromResolve = container.Resolve(); + + Assert.That(fromResolve, Is.Not.Null.And.EqualTo(fromCallback)); + } + + { + NoDependencyServiceA fromCallback = null; + + var builder = new ContainerBuilder(); + builder.Register(_ => new NoDependencyServiceA(), Lifetime.Scoped, (service, _) => fromCallback = service); + + var container = builder.Build(); + + var fromResolve = container.Resolve(); + + Assert.That(fromResolve, Is.Not.Null.And.EqualTo(fromCallback)); + } + } } }