| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- using Invercargill;
- using Invercargill.DataStructures;
- namespace Inversion {
- /**
- * Error domain for container-related errors.
- */
- public errordomain ContainerError {
- /**
- * The requested type is not registered in the container.
- */
- NOT_REGISTERED,
- /**
- * Cycle detected in injection
- */
- CYCLE_DETECTED,
- /**
- * Resolved to a registration with an invalid lifecycle for the lifecycle of the scope
- */
- ILLEGAL_LIFECYCLE_COMBINATION
- }
- /**
- * The inversion of control container that manages component registrations and lifecycles.
- *
- * The container is responsible for:
- * - Storing component registrations
- * - Managing singleton instances
- * - Creating scopes for scoped instance management
- * - Resolving dependencies
- *
- * Multiple registrations can be mapped to a single service type. When resolving,
- * you can get a single instance (any one) or all instances.
- *
- * Example usage:
- * {{{
- * var container = new Container();
- *
- * // Register a type with a factory delegate
- * container.register(typeof(MyService), (scope) => new MyService())
- * .with_lifecycle(Lifecycle.SINGLETON);
- *
- * // Register a type as multiple interfaces
- * container.register(typeof(MyImplementation), (scope) => new MyImplementation())
- * .as_type(typeof(IServiceA))
- * .as_type(typeof(IServiceB))
- * .with_lifecycle(Lifecycle.SCOPED)
- * .build();
- *
- * // Register with a custom Factory instance
- * var factory = new MyCustomFactory();
- * container.register_with_factory_instance(typeof(MyService), factory)
- * .as_type(typeof(IService))
- * .build();
- * }}}
- */
- public class Container : Object {
- private Catalogue<Type, Registration> registrations;
- private Dictionary<Registration, Object> singletons;
- public Container() {
- this.registrations = new Catalogue<Type, Registration>();
- this.singletons = new Dictionary<Registration, Object>();
- register_singleton<Container>(s => this);
- }
- public Registration register_factory_type(Type implementation_type, Factory factory, Lifecycle lifecycle) {
- var registration = new Registration(implementation_type, factory, lifecycle);
- this.registrations.add(implementation_type, registration);
- // Add subsequent aliases added to this registration
- registration.alias_added.connect(t => {
- this.registrations.add(t, registration);
- });
-
- return registration;
- }
- public Registration register_factory<T>(Factory factory, Lifecycle lifecycle) {
- return register_factory_type(typeof(T), factory, lifecycle);
- }
- public Registration register_type(Type implementation_type, owned FactoryDelegate factory_func, Lifecycle lifecycle) {
- var delegate_factory = new DelegateFactory((owned)factory_func);
- return register_factory_type(implementation_type, delegate_factory, lifecycle);
- }
- public Registration register<T>(owned FactoryDelegate factory_func, Lifecycle lifecycle) {
- return register_type(typeof(T), (owned)factory_func, lifecycle);
- }
- public Registration register_transient<T>(owned FactoryDelegate factory_func) {
- return register<T>((owned)factory_func, Lifecycle.TRANSIENT);
- }
- public Registration register_scoped<T>(owned FactoryDelegate factory_func) {
- return register<T>((owned)factory_func, Lifecycle.SCOPED);
- }
- public Registration register_singleton<T>(owned FactoryDelegate factory_func) {
- return register<T>((owned)factory_func, Lifecycle.SINGLETON);
- }
- public bool is_registered(Type type) {
- return this.registrations.has(type);
- }
- public Registration get_registration(Type service_type) throws ContainerError {
- try {
- return this.registrations.get_any(service_type);
- } catch (Error e) {
- throw new ContainerError.NOT_REGISTERED(
- "Type %s is not registered in the container: %s".printf(service_type.name(), e.message)
- );
- }
- }
- /**
- * Gets all registrations for a service type.
- *
- * @param service_type The type to look up
- * @return An enumerable of all registrations for the type (may be empty)
- */
- public Enumerable<Registration> get_registrations(Type service_type) {
- return this.registrations.get_or_empty(service_type);
- }
- /**
- * Gets or creates a singleton instance for a registration.
- *
- * @param registration The registration to get the singleton for
- * @param scope The current scope for dependency resolution
- * @return The singleton instance
- * @throws Error if instance creation fails
- */
- internal Object get_or_create_singleton(Registration registration, Type requested_type) throws Error {
- Object instance;
- if (!this.singletons.try_get(registration, out instance)) {
- var singleton_scope = new Scope(this, Lifecycle.SINGLETON);
- instance = create_with_injection_context(singleton_scope, requested_type, registration);
- this.singletons.set(registration, instance);
- }
- return instance;
- }
- /**
- * Creates a new scope for resolving scoped instances.
- *
- * @return A new Scope tied to this container
- */
- public Scope create_scope() {
- return new Scope(this, Lifecycle.SCOPED);
- }
- public Scope create_transient_scope() {
- return new Scope(this, Lifecycle.TRANSIENT);
- }
- }
- }
|