diff --git a/lib/ioc_container.dart b/lib/ioc_container.dart index 710cb86..af9499a 100644 --- a/lib/ioc_container.dart +++ b/lib/ioc_container.dart @@ -21,11 +21,7 @@ class ServiceDefinition { this.isSingleton = false, this.dispose, this.disposeAsync, - }) : assert( - !isSingleton || dispose == null, - 'Singleton factories cannot have a dispose method', - ), - assert( + }) : assert( dispose == null || disposeAsync == null, "Service definitions can't have both dispose and disposeAsync", ); @@ -154,12 +150,14 @@ class IocContainerBuilder { void addSingleton( T Function( IocContainer container, - ) factory, - ) => + ) factory, { + void Function(T service)? dispose, + }) => addServiceDefinition( ServiceDefinition( (container) => factory(container), isSingleton: true, + dispose: dispose, ), ); @@ -196,12 +194,14 @@ class IocContainerBuilder { void addSingletonAsync( Future Function( IocContainer container, - ) factory, - ) => + ) factory, { + Future Function(T service)? disposeAsync, + }) => addServiceDefinition>( ServiceDefinition>( isSingleton: true, (container) async => factory(container), + disposeAsync: (service) async => disposeAsync?.call(await service), ), ); } diff --git a/test/ioc_container_test.dart b/test/ioc_container_test.dart index 7234bca..a764348 100644 --- a/test/ioc_container_test.dart +++ b/test/ioc_container_test.dart @@ -33,6 +33,8 @@ extension TestIocContainerExtensions on IocContainer { class A { A(this.name); final String name; + bool disposed = false; + void dispose() => disposed = true; } class B { @@ -157,7 +159,10 @@ void main() { test('With Scoping And Disposing', () async { final a = A('a'); final builder = IocContainerBuilder() - ..addSingleton((c) => a) + ..addSingleton( + (c) => a, + dispose: (a) => a.dispose(), + ) ..add((i) => B(i.get())) ..add( (i) => C(i.get()), @@ -177,6 +182,7 @@ void main() { //This also works if we don't use await above //await Future.delayed(const Duration(milliseconds: 100)); + expect(a.disposed, true); expect(d.disposed, true); expect(d.c.disposed, true); expect(container().disposed, false); @@ -878,7 +884,7 @@ void main() { ); }); - test('Test addAsyncSingleton', () async { + test('Test addAsyncSingleton With Dispose', () async { var futureCounter = 0; final builder = IocContainerBuilder() @@ -892,6 +898,7 @@ void main() { return A('a'); }, ), + disposeAsync: (service) async => service.dispose(), ); final container = builder.toContainer(); @@ -911,5 +918,10 @@ void main() { //Expect the future only ran once expect(futureCounter, 1); + + final scope = container.scoped(useExistingSingletons: true); + await scope.dispose(); + + expect(as[0].disposed, true); }); }