find<S> method
Finds and returns a registered instance of type S.
This method performs a hierarchical lookup:
- Local Check: Checks the current scope.
- Parent Check: Recursively checks parent scopes.
If the dependency is found but not yet instantiated (lazy), it will be created.
Throws an Exception if S is not registered in this scope or any ancestor.
Implementation
S find<S>({String? tag}) {
_ensureUsable();
// Tag-less singleton lookups use a direct instance cache.
if (tag == null) {
final cached = _instanceCache[S];
if (cached != null) {
return cached as S;
}
// Type registry is the primary lookup path for untagged dependencies.
final info = _typeRegistry[S];
if (info != null) {
// Reuse existing singleton and seed instance cache.
final instance = info.instance;
if (instance != null && !info.isFactory) {
_instanceCache[S] = instance;
return instance as S;
}
// Lazy registrations instantiate on first resolve.
final result = _findLocal<S>(
info as LevitDependency<S>,
LevitScopeKey.of<S>().debugString,
null,
);
// Factories must never be cached.
if (!info.isFactory && info.instance != null) {
_instanceCache[S] = info.instance;
}
return result;
}
final aliasKey = LevitScopeKey.of<S>();
final canonicalKey = _aliases[aliasKey];
if (canonicalKey != null) {
final result = _findAliasLocal<S>(
aliasKey: aliasKey,
canonicalKey: canonicalKey,
);
_instanceCache[S] = result;
return result;
}
// Parent resolution cache avoids repeated ancestor traversal.
final cachedScope = _typeResolutionCache[S];
if (cachedScope != null) {
try {
return cachedScope.find<S>();
} catch (_) {
_typeResolutionCache.remove(S);
}
}
// Parent fallback preserves scope hierarchy resolution.
if (_parentScope != null) {
try {
final instance = _parentScope!.find<S>();
_typeResolutionCache[S] = _parentScope!;
return instance;
} catch (_) {
// Cached parent may be stale after resets; fall through.
}
}
throw Exception(
'LevitScope($name): Type "$S" is not registered.\n'
'Not found in scope or any parent.',
);
}
// Tagged lookups use composite key registries.
final key = _getKey<S>(tag);
final keyString = key.debugString;
final info = _registry[key];
if (info != null) {
return _findLocal<S>(info as LevitDependency<S>, keyString, tag);
}
final canonicalKey = _aliases[key];
if (canonicalKey != null) {
return _findAliasLocal<S>(
aliasKey: key,
canonicalKey: canonicalKey,
);
}
// Reuse cached ancestor that previously resolved this key.
final cachedScope = _readCachedScope(key);
if (cachedScope != null) {
try {
return cachedScope.find<S>(tag: tag);
} catch (_) {
_resolutionCache.remove(key);
}
}
// Fallback to parent scope chain.
if (_parentScope != null) {
try {
final instance = _parentScope!.find<S>(tag: tag);
_cacheScope(key, _parentScope!);
return instance;
} catch (_) {
// Cached ancestry may be invalidated by parent resets.
}
}
throw Exception(
'LevitScope($name): Type "$S" with tag "$tag" is not registered.\n'
'Not found in scope or any parent.',
);
}