Lifecycle defines instance lifetime behavior for registered components. Three lifecycles are supported: transient (new instance per resolve), scoped (one instance per scope), and singleton (one instance per container).
Inversion
public enum Lifecycle
TRANSIENTA new instance is created every time the component is requested.
container.register_transient<MyService>((s) => new MyService());
var scope = container.create_scope();
var a = scope.resolve<MyService>(); // New instance
var b = scope.resolve<MyService>(); // Different instance
// a != b
Use for:
SCOPEDA single instance is created per scope. Within the same scope, the same instance is returned for each request.
container.register_scoped<UserSession>((s) => new UserSession());
var scope1 = container.create_scope();
var scope2 = container.create_scope();
var a1 = scope1.resolve<UserSession>(); // Instance A
var a2 = scope1.resolve<UserSession>(); // Same Instance A
// a1 == a2
var b1 = scope2.resolve<UserSession>(); // Instance B (different)
// a1 != b1
Use for:
SINGLETONA single instance is created for the lifetime of the container. The same instance is returned for all requests across all scopes.
container.register_singleton<Configuration>((s) => new Configuration());
var scope1 = container.create_scope();
var scope2 = container.create_scope();
var a = scope1.resolve<Configuration>(); // Instance A
var b = scope2.resolve<Configuration>(); // Same Instance A
// a == b
Use for:
When resolving from a singleton context, scoped registrations cannot be resolved:
// This throws ILLEGAL_LIFECYCLE_COMBINATION
// A singleton cannot depend on a scoped service
public class SingletonService : Object {
private ScopedService scoped = inject<ScopedService>(); // Error at runtime!
}
container.register_singleton<SingletonService>((s) => new SingletonService());
container.register_scoped<ScopedService>((s) => new ScopedService());
var scope = container.create_scope();
scope.resolve<SingletonService>(); // Throws!
Scope-local registrations cannot be singletons:
// Compile-time precondition failure
scope.register_local<MyService>((s) => new MyService(), Lifecycle.SINGLETON);
// Error: requires (lifecycle != Lifecycle.SINGLETON)
| Method | Lifecycle |
|---|---|
register_transient<T>() |
TRANSIENT |
register_scoped<T>() |
SCOPED |
register_singleton<T>() |
SINGLETON |
register<T>(..., lifecycle) |
Specified |
| Lifecycle | Instance Count | Scope Behavior | Memory |
|---|---|---|---|
| TRANSIENT | Per resolve | New each time | Highest |
| SCOPED | Per scope | Shared in scope | Medium |
| SINGLETON | Per container | Shared globally | Lowest |
public class AppConfig : Object {
public string database_path { get; set; }
}
container.register_singleton<AppConfig>((s) => {
var config = new AppConfig();
config.database_path = "/data/app.db";
return config;
});
public class RequestContext : Object {
public string request_id { get; construct set; }
public User? current_user { get; set; }
}
// In request handler
void handle_request(Request req) {
var scope = container.create_scope();
scope.register_local_scoped<RequestContext>((s) => {
var ctx = new RequestContext();
ctx.request_id = req.id;
return ctx;
});
var handler = scope.resolve<RequestHandler>();
handler.process();
}
public interface IRequestHandler : Object {
public abstract void handle(Request req);
}
container.register_transient<CreateUserHandler>((s) => new CreateUserHandler())
.as_type(typeof(IRequestHandler));
container.register_transient<DeleteUserHandler>((s) => new DeleteUserHandler())
.as_type(typeof(IRequestHandler));
// Each resolution creates new handler instances
var handlers = scope.resolve_all<IRequestHandler>();
The Lifecycle enum defines three instance lifetime behaviors: TRANSIENT for per-resolution instances, SCOPED for per-scope instances, and SINGLETON for container-wide single instances.