From b722782a7d45be216fcc4bee01bed03534700be8 Mon Sep 17 00:00:00 2001 From: Abdullah <89297042+AzazelSensei@users.noreply.github.com> Date: Thu, 13 Aug 2026 12:30:12 +0300 Subject: [PATCH] feat: add ignoreIfNotRegistered to unregister Default still throws when the type or instance is missing. Pass ignoreIfNotRegistered: true if a second dispose should no-op. --- lib/get_it.dart | 3 +++ lib/get_it_impl.dart | 20 +++++++++++++--- test/get_it_test.dart | 54 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 3 deletions(-) diff --git a/lib/get_it.dart b/lib/get_it.dart index 2a5e022..2aaca19 100644 --- a/lib/get_it.dart +++ b/lib/get_it.dart @@ -801,11 +801,14 @@ abstract class GetIt { /// if referenceCount is 0 /// [ignoreReferenceCount] if `true` it will ignore the reference count and unregister the object /// only use this if you know what you are doing + /// [ignoreIfNotRegistered] if `true` a missing registration is a no-op instead of + /// throwing. Defaults to `false` so a second dispose still surfaces a logic error. FutureOr unregister({ Object? instance, String? instanceName, FutureOr Function(T)? disposingFunction, bool ignoreReferenceCount = false, + bool ignoreIfNotRegistered = false, }); /// returns a Future that completes if all asynchronously created Singletons and any diff --git a/lib/get_it_impl.dart b/lib/get_it_impl.dart index db09764..33b8fce 100644 --- a/lib/get_it_impl.dart +++ b/lib/get_it_impl.dart @@ -1414,6 +1414,8 @@ class _GetItImplementation implements GetIt { /// If you have provided an disposing function when you registered the object that one will be called automatically /// If you have enabled reference counting when registering, [unregister] will only unregister and dispose the object /// if referenceCount is 0 + /// [ignoreIfNotRegistered] if `true` a missing registration is a no-op instead of + /// throwing. Defaults to `false`. /// @override FutureOr unregister({ @@ -1421,10 +1423,22 @@ class _GetItImplementation implements GetIt { String? instanceName, FutureOr Function(T)? disposingFunction, bool ignoreReferenceCount = false, + bool ignoreIfNotRegistered = false, }) async { - final registrationToRemove = instance != null - ? _findRegistrationByInstance(instance) - : _findRegistrationByNameAndType(instanceName); + final _ObjectRegistration? registrationToRemove; + if (instance != null) { + registrationToRemove = ignoreIfNotRegistered + ? _findFirstRegistrationByInstanceOrNull(instance) + : _findRegistrationByInstance(instance); + } else { + registrationToRemove = ignoreIfNotRegistered + ? _findFirstRegistrationByNameAndTypeOrNull(instanceName) + : _findRegistrationByNameAndType(instanceName); + } + + if (registrationToRemove == null) { + return; + } throwIf( registrationToRemove.objectsWaiting.isNotEmpty, diff --git a/test/get_it_test.dart b/test/get_it_test.dart index de2e5c1..eda309d 100644 --- a/test/get_it_test.dart +++ b/test/get_it_test.dart @@ -1151,6 +1151,60 @@ void main() { throwsStateError, ); }); + + test('unregister throws by default if not registered', () async { + final getIt = GetIt.instance; + + await expectLater(getIt.unregister(), throwsStateError); + + getIt.registerSingleton(TestClass()); + await getIt.unregister(); + + await expectLater(getIt.unregister(), throwsStateError); + }); + + test('unregister ignoreIfNotRegistered no-ops if missing', () async { + final getIt = GetIt.instance; + disposeCounter = 0; + + await getIt.unregister(ignoreIfNotRegistered: true); + + getIt.registerSingleton( + TestClass(), + dispose: (testClass) { + testClass.dispose(); + }, + ); + + await getIt.unregister(); + expect(disposeCounter, 1); + expect(getIt.isRegistered(), isFalse); + + await getIt.unregister(ignoreIfNotRegistered: true); + expect(disposeCounter, 1); + expect(getIt.isRegistered(), isFalse); + }); + + test('unregister ignoreIfNotRegistered by instance no-ops if missing', + () async { + final getIt = GetIt.instance; + final instance = TestClass(); + + await getIt.unregister( + instance: instance, + ignoreIfNotRegistered: true, + ); + + getIt.registerSingleton(instance); + await getIt.unregister(instance: instance); + + await getIt.unregister( + instance: instance, + ignoreIfNotRegistered: true, + ); + expect(getIt.isRegistered(), isFalse); + }); + test('change registration name with type and name', () async { final getIt = GetIt.instance; disposeCounter = 0;