using Inversion; /** * Injection Demo Example * * This example demonstrates the inject() method for property/field injection. * The inject method allows dependencies to be resolved during object construction * without requiring explicit constructor parameters. * * Key concepts: * - Using inject() for field initialization * - The injection context is automatically set up during container resolution * - Multiple dependencies can be injected in the same class */ public class InjectionDemoExample : Object { // Define service interfaces public interface IHandler : Object { public abstract void handle(string request); } public interface IRepository : Object { public abstract string get_data(); } // Console handler implementation public class ConsoleHandler : Object, IHandler { public void handle(string request) { stdout.printf("[HANDLER] Processing: %s\n", request); } } // Memory repository implementation public class MemoryRepository : Object, IRepository { public string get_data() { return "Sample data from repository"; } } // A service that uses inject() for dependency injection // This class demonstrates field injection using the inject method public class Controller : Object { // Dependencies are injected during object construction private IHandler handler = inject(); private IRepository repository = inject(); public void process_request(string request) { var data = this.repository.get_data(); stdout.printf("[CONTROLLER] Retrieved data: %s\n", data); this.handler.handle(request); } } // Another service demonstrating nested injection public class ApiService : Object { private Controller controller = inject(); public void execute(string request) { stdout.printf("[API] Executing request: %s\n", request); this.controller.process_request(request); } } public static int main(string[] args) { stdout.printf("=== Inversion IoC Injection Demo ===\n\n"); // Create the container var container = new Container(); // Register all services with factory delegates container.register_singleton((scope) => new ConsoleHandler()) .as_type(typeof(IHandler)); container.register_singleton((scope) => new MemoryRepository()) .as_type(typeof(IRepository)); // Register Controller - it will use inject() to resolve its dependencies container.register_scoped((scope) => new Controller()); // Register ApiService - demonstrates nested injection container.register_transient((scope) => new ApiService()); stdout.printf("Registered services:\n"); stdout.printf(" - ConsoleHandler as IHandler (Singleton)\n"); stdout.printf(" - MemoryRepository as IRepository (Singleton)\n"); stdout.printf(" - Controller (Scoped) - uses inject()\n"); stdout.printf(" - ApiService (Transient) - uses inject()\n\n"); // Create a scope var scope = container.create_scope(); try { stdout.printf("--- Resolving ApiService (demonstrates nested injection) ---\n\n"); // Resolve ApiService - this will trigger: // 1. ApiService construction -> inject() // 2. Controller construction -> inject() and inject() var api_service = scope.resolve(); api_service.execute("Test request #1"); stdout.printf("\n--- Resolving Controller directly ---\n\n"); // Resolve Controller directly var controller = scope.resolve(); controller.process_request("Test request #2"); // Verify scoped behavior - same controller instance within scope var controller2 = scope.resolve(); if (controller == controller2) { stdout.printf("\n✓ Scoped working: Same Controller instance within scope\n"); } stdout.printf("\n--- Creating another scope ---\n\n"); // Create another scope - should get a new Controller instance var scope2 = container.create_scope(); var controller_in_scope2 = scope2.resolve(); controller_in_scope2.process_request("Test request #3"); if (controller != controller_in_scope2) { stdout.printf("\n✓ Scoped working: Different Controller instance in different scope\n"); } } catch (Error e) { stderr.printf("Error: %s\n", e.message); return 1; } stdout.printf("\n=== Example Complete ===\n"); return 0; } }