Practical examples demonstrating Inversion IoC container features including basic registration, lifecycle management, field injection, multi-registration, and scope-local registrations.
using Inversion;
public interface ILogger : Object {
public abstract void log(string message);
}
public class ConsoleLogger : Object, ILogger {
public void log(string message) {
stdout.printf("[LOG] %s\n", message);
}
}
public static int main(string[] args) {
var container = new Container();
// Register implementation as interface
container.register_singleton<ConsoleLogger>((scope) => new ConsoleLogger())
.as_type(typeof(ILogger));
// Create scope and resolve
var scope = container.create_scope();
var logger = scope.resolve<ILogger>();
logger.log("Hello, World!");
return 0;
}
public class Configuration : Object {
public string db_path { get; set; }
}
container.register_singleton<Configuration>((s) => {
var config = new Configuration();
config.db_path = "/data/app.db";
return config;
});
// Same instance across all scopes
var scope1 = container.create_scope();
var scope2 = container.create_scope();
var config1 = scope1.resolve<Configuration>();
var config2 = scope2.resolve<Configuration>();
// config1 == config2
public class UserSession : Object {
public string user_id { get; set; }
}
container.register_scoped<UserSession>((s) => new UserSession());
// Same instance within scope
var scope = container.create_scope();
var session1 = scope.resolve<UserSession>();
var session2 = scope.resolve<UserSession>();
// session1 == session2
// Different instance in different scope
var other_scope = container.create_scope();
var session3 = other_scope.resolve<UserSession>();
// session1 != session3
public class RequestHandler : Object {
public void handle(string request) {
stdout.printf("Handling: %s\n", request);
}
}
container.register_transient<RequestHandler>((s) => new RequestHandler());
var scope = container.create_scope();
var handler1 = scope.resolve<RequestHandler>();
var handler2 = scope.resolve<RequestHandler>();
// handler1 != handler2
public interface IRepository : Object {
public abstract string get_data();
}
public interface IHandler : Object {
public abstract void handle(string request);
}
public class UserService : Object {
// Dependencies injected during construction
private IRepository repo = inject<IRepository>();
private IHandler handler = inject<IHandler>();
public void process() {
var data = repo.get_data();
handler.handle(data);
}
}
// Register dependencies
container.register_singleton<MemoryRepository>((s) => new MemoryRepository())
.as_type(typeof(IRepository));
container.register_singleton<ConsoleHandler>((s) => new ConsoleHandler())
.as_type(typeof(IHandler));
container.register_scoped<UserService>((s) => new UserService());
// Resolve - dependencies injected automatically
var scope = container.create_scope();
var service = scope.resolve<UserService>();
service.process();
public interface IValidator : Object {
public abstract bool validate(Object obj);
}
public class EmailValidator : Object, IValidator {
public bool validate(Object obj) {
stdout.printf("Validating email...\n");
return true;
}
}
public class PhoneValidator : Object, IValidator {
public bool validate(Object obj) {
stdout.printf("Validating phone...\n");
return true;
}
}
// Register multiple implementations
container.register_singleton<EmailValidator>((s) => new EmailValidator())
.as_type(typeof(IValidator));
container.register_singleton<PhoneValidator>((s) => new PhoneValidator())
.as_type(typeof(IValidator));
// Resolve all implementations
var scope = container.create_scope();
var validators = scope.resolve_all<IValidator>();
validators.iterate((obj) => {
var validator = (IValidator) obj;
validator.validate(data);
});
public class ValidationService : Object {
// Inject all IValidator implementations
private Lot<IValidator> validators = inject_all<IValidator>();
public bool validate_all(Object obj) {
foreach (var validator in validators) {
if (!validator.validate(obj)) {
return false;
}
}
return true;
}
}
public class RequestContext : Object {
public string request_id { get; set; }
public string path { get; set; }
}
// Container has application-wide services
var container = new Container();
container.register_singleton<Database>((s) => new Database());
// Each request creates a scope with request-specific context
void handle_request(string request_id, string path) {
var scope = container.create_scope();
// Register request-specific context (only visible in this scope)
scope.register_local_scoped<RequestContext>((s) => {
var ctx = new RequestContext();
ctx.request_id = request_id;
ctx.path = path;
return ctx;
});
// Handlers can resolve RequestContext
var handler = scope.resolve<RequestHandler>();
handler.process();
}
public class OrderService : Object {
private IOrderRepository repo;
private ILogger logger;
public OrderService(IOrderRepository repo, ILogger logger) {
this.repo = repo;
this.logger = logger;
}
}
container.register_scoped<OrderService>((scope) => {
// Resolve dependencies from scope
var repo = scope.resolve<IOrderRepository>();
var logger = scope.resolve<ILogger>();
return new OrderService(repo, logger);
});
public interface IRepository : Object {
public abstract Object? find(int id);
}
public interface ICache : Object {
public abstract void cache(Object obj);
}
public class CachedRepository : Object, IRepository, ICache {
public Object? find(int id) { return null; }
public void cache(Object obj) { }
}
// Register as both interfaces
container.register_singleton<CachedRepository>((s) => new CachedRepository())
.as_type(typeof(IRepository))
.as_type(typeof(ICache));
// Can resolve by either interface
var scope = container.create_scope();
var repo = scope.resolve<IRepository>();
var cache = scope.resolve<ICache>();
// Both point to same CachedRepository instance
try {
var service = scope.resolve<IMyService>();
service.do_work();
} catch (ContainerError.NOT_REGISTERED e) {
stderr.printf("Service not registered: %s\n", e.message);
} catch (ContainerError.CYCLE_DETECTED e) {
stderr.printf("Circular dependency: %s\n", e.message);
} catch (ContainerError.ILLEGAL_LIFECYCLE_COMBINATION e) {
stderr.printf("Lifecycle error: %s\n", e.message);
} catch (Error e) {
stderr.printf("Error: %s\n", e.message);
}
public class ApplicationController : Object {
private static Container container;
static construct {
container = new Container();
// Application-wide services
container.register_singleton<Database>((s) => new Database("app.db"));
container.register_singleton<Cache>((s) => new RedisCache());
// Per-request services
container.register_scoped<UserSession>((s) => new UserSession());
container.register_transient<RequestHandler>((s) => new RequestHandler());
}
public void handle_request(Request req, Response res) {
var scope = container.create_scope();
// Register request context
scope.register_local_scoped<RequestContext>((s) => {
return new RequestContext(req.id, req.path);
});
try {
var handler = scope.resolve<RequestHandler>();
handler.handle(req, res);
} catch (Error e) {
res.error(500, e.message);
}
}
}
These examples demonstrate Inversion IoC patterns including basic registration, lifecycle management, field injection with inject(), multi-registration with resolve_all(), and scope-local registrations for per-request contexts.