Skip to main content

Circular Dependency Detection

InjectContainer automatically detects and reports circular dependencies during resolution, preventing infinite instantiation loops and stack overflows.

How it works

TInject maintains a FDependencyStack: TList<string> that tracks the chain of services being resolved at any point in time.

Every call to GetTry<T> or GetInterfaceTry<I> wraps resolution in a push/pop pair:

_PushDependency(LTag);
try
// ... resolve the service
finally
_PopDependency;
end;

_PushDependency calls _CheckCircularDependency before adding the name to the stack:

procedure TInject._CheckCircularDependency(const AServiceName: string);
var
LFor: Integer;
begin
for LFor := 0 to FDependencyStack.Count - 1 do
begin
if FDependencyStack[LFor] = AServiceName then
begin
// Build full chain string up to the repeated node
raise ECircularDependency.Create(
Format('Circular dependency detected: %s', [LDependencyChain])
);
end;
end;
end;

Error raised

ECircularDependency = class(EInjectException);

The exception message includes the full chain, e.g.:

Circular dependency detected: TServiceA -> TServiceB -> TServiceC -> TServiceA

Example scenario

// TServiceA.Create resolves TServiceB
// TServiceB.Create resolves TServiceA ← circular!

GetInjector.SingletonLazy<TServiceA>;
GetInjector.SingletonLazy<TServiceB>;

try
var LA := GetInjector.Get<TServiceA>;
except
on E: ECircularDependency do
Writeln(E.Message);
// Circular dependency detected: TServiceA -> TServiceB -> TServiceA
end;

How to fix circular dependencies

Circular dependencies usually signal a design issue. Common fixes:

PatternFix
A → B → AExtract a shared C that both A and B depend on; neither depends on the other
Service needs a late referenceInject a factory TFunc<IB> instead of IB directly — resolved lazily
Infrastructure loopUse event callbacks (OnCreate) to do the second wiring after construction

Stack pop on exception

_PopDependency is called in the finally block, so the stack is always consistent even when _CheckCircularDependency raises or when service construction fails for another reason.