SingletonBase
On this page
Namespace: Nalix.Framework.Injection.DI (and Nalix.Framework)
Assembly: Nalix.Framework
SingletonBase<T> (public abstract class SingletonBase<T> : IDisposable where T : class) is the thread-safe, Native AOT-compatible generic singleton base class used by framework services such as InstanceManager and ReportRegistry.
Source Mapping
src/Nalix.Framework/Injection/DI/SingletonBase.cssrc/Nalix.Framework/Injection/DI/SingletonActivatorCache.cssrc/Nalix.Framework/ReportRegistry.csanalyzers/Nalix.Analyzers.Generators/InstanceGenerator.cs
How Native AOT Activation Works
Unlike traditional generic singletons that rely on Activator.CreateInstance or Expression.Compile at runtime, SingletonBase<T> resolves its constructor delegate once per closed generic type from SingletonActivatorCache.GetRequired<T>():
- At compile time,
InstanceGeneratordiscovers every non-abstract subclass ofSingletonBase<T>(as well as[Injectable]classes) and emits a[ModuleInitializer]inInstanceActivators.g.csthat registers a direct constructor lambda (static () => new MyService()) intoSingletonActivatorCache. - At runtime,
SingletonBase<T>wraps that factory in aLazy<T>configured withLazyThreadSafetyMode.ExecutionAndPublication.
SingletonBase<T> Members
| Member | Signature | Description |
|---|---|---|
Instance | public static T Instance { get; } | Returns the singleton instance, creating it on first access via Lazy<T>. |
IsCreated | public static bool IsCreated { get; } | Returns true if the singleton instance has already been created without forcing creation. |
TryGetInstance | public static bool TryGetInstance([MaybeNullWhen(false)] out T instance) | Returns true and the existing instance if already created; otherwise false without creating it. |
EnsureCreated | public static void EnsureCreated() | Forces eager creation of the singleton instance during application warm-up. |
Dispose() | public void Dispose() | Disposes the singleton instance (idempotent via atomic Interlocked.Exchange). |
Dispose(bool) | protected virtual void Dispose(bool disposing) | Calls DisposeManaged() once when disposing is true. |
DisposeManaged() | protected virtual void DisposeManaged() | Override in subclasses to release managed resources on disposal. |
Usage Example
using Nalix.Framework.Injection.DI;
public sealed class MetricsAggregator : SingletonBase<MetricsAggregator>
{
// Internal or public parameterless constructor is called by InstanceGenerator's ModuleInitializer
internal MetricsAggregator()
{
}
protected override void DisposeManaged()
{
// Clean up managed resources
}
}
// Warm up at startup
MetricsAggregator.EnsureCreated();
// Access anywhere
MetricsAggregator aggregator = MetricsAggregator.Instance;
ReportRegistry (Nalix.Framework.ReportRegistry)
ReportRegistry (public sealed class ReportRegistry : SingletonBase<ReportRegistry>, IReportable) is a thread-safe diagnostic registry mapping (Enum Key, Type Type) pairs to IReportable component instances. InstanceManager automatically registers built-in CoreTelemetryTarget IReportable services (ITaskManager, IConnectionHub, IBufferPoolManager, IObjectPoolManager, ISessionService, etc.) into ReportRegistry.Instance; custom application IReportable services should call ReportRegistry.Instance.Register(key, instance) directly:
void Register<T>(Enum key, T instance) where T : class, IReportable— Registersinstanceunder(key, typeof(T)),(key, instance.GetType()), and all implementedIReportableinterfaces.T? Get<T>(Enum key) where T : class, IReportable— Retrieves a registered reportable component by enum key and type.bool Unregister<T>(Enum key) where T : class, IReportable— Removes the registration forkeyandtypeof(T).void Clear()— Clears all registrations.string GenerateReport()/void WriteReportData(Utf8JsonWriter writer)/void WriteReportData<T>(Utf8JsonWriter writer)— Aggregates text or structured JSON reports across registered components.