Skip to main content

Architecture Overview

Unit structure

InjectContainer is composed of five units, each with a single responsibility:

UnitClass(es)Responsibility
Inject.pasTInjectPublic facade — registration, resolution, logging, RTTI cache
Inject.Container.pasTInjectContainerBase container — shared dictionary state
Inject.Factory.pasTInjectFactoryRTTI-driven object construction
Inject.Service.pasTServiceData, TInjectionModeService descriptor — holds class, GUID, instance, lifecycle
Inject.Events.pasTInjectEvents, TConstructorCallbackLifecycle callback holder
Inject.Service.Abstract.pasTServiceDataAbstractBase class for services that need an FOwner: TInject reference

Inheritance chain

TObject
└── TInjectAbstract
└── TInjectContainer (Inject.Container)
└── TInject (Inject)

TInjectContainer owns and initializes all shared data structures. TInject adds the public API, RTTI cache, logging, and dependency-stack tracking.

Data flow: registration

caller → TInject.Singleton<T>

├─ check FRepositoryReference (duplicate guard)
├─ add T.ClassName → TServiceData to FRepositoryReference
├─ FInjectorFactory.FactorySingleton<T>() ← constructs TServiceData via RTTI
├─ add TServiceData to FInstances
└─ _AddEvents<T>() ← stores OnCreate/OnDestroy/OnParams in FInjectorEvents

Data flow: resolution

caller → TInject.Get<T>

├─ GetTry<T>
│ ├─ _PushDependency(T.ClassName) ← circular-dependency check
│ ├─ look up FInstances[T.ClassName]
│ ├─ if nil → FInjectorFactory.FactorySingleton<T> (lazy path)
│ ├─ _ResolverParams(ServiceClass) ← auto-wire constructor args via RTTI cache
│ ├─ TServiceData.GetInstance<T>(Events, Params)
│ │ ├─ imSingleton → reuse FInstance (or construct once)
│ │ └─ imFactory → construct fresh instance every time
│ └─ _PopDependency

└─ if not found → cascade into child TInject instances in FInstances

Internal dictionaries

FieldTypeKeysValues
FRepositoryReferenceTDictionary<string, TClass>T.ClassName or ATagThe registered TClass
FRepositoryInterfaceTDictionary<string, TPair<TClass, TGUID>>GUIDToString(I) or ATag(TClass, TGUID) pair
FInstancesTObjectDictionary<string, TServiceData>Same keysTServiceData descriptor (owns values)
FInjectorEventsTObjectDictionary<string, TInjectEvents>Same keysTInjectEvents callback holder
FTypeCacheTDictionary<string, TRttiType>IntToHex(TClass pointer)TRttiType
FMethodCacheTDictionary<string, TRttiMethod>IntToHex(TClass pointer).MethodNameTRttiMethod
FDependencyStackTList<string>Service names currently being resolved

Global singleton pattern

The framework exposes a process-wide injector via:

var
GPInjector : PInject = nil; // pointer to the global TInject
GInjectorLock: TCriticalSection; // guards pointer access

GetInjector acquires GInjectorLock before returning GPInjector^, making the global accessor thread-safe. The instance is created in initialization and freed in finalization.