Container.vala 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. using Invercargill;
  2. using Invercargill.DataStructures;
  3. namespace Inversion {
  4. /**
  5. * Error domain for container-related errors.
  6. */
  7. public errordomain ContainerError {
  8. /**
  9. * The requested type is not registered in the container.
  10. */
  11. NOT_REGISTERED,
  12. /**
  13. * Cycle detected in injection
  14. */
  15. CYCLE_DETECTED,
  16. /**
  17. * Resolved to a registration with an invalid lifecycle for the lifecycle of the scope
  18. */
  19. ILLEGAL_LIFECYCLE_COMBINATION
  20. }
  21. /**
  22. * The inversion of control container that manages component registrations and lifecycles.
  23. *
  24. * The container is responsible for:
  25. * - Storing component registrations
  26. * - Managing singleton instances
  27. * - Creating scopes for scoped instance management
  28. * - Resolving dependencies
  29. *
  30. * Multiple registrations can be mapped to a single service type. When resolving,
  31. * you can get a single instance (any one) or all instances.
  32. *
  33. * Example usage:
  34. * {{{
  35. * var container = new Container();
  36. *
  37. * // Register a type with a factory delegate
  38. * container.register(typeof(MyService), (scope) => new MyService())
  39. * .with_lifecycle(Lifecycle.SINGLETON);
  40. *
  41. * // Register a type as multiple interfaces
  42. * container.register(typeof(MyImplementation), (scope) => new MyImplementation())
  43. * .as_type(typeof(IServiceA))
  44. * .as_type(typeof(IServiceB))
  45. * .with_lifecycle(Lifecycle.SCOPED)
  46. * .build();
  47. *
  48. * // Register with a custom Factory instance
  49. * var factory = new MyCustomFactory();
  50. * container.register_with_factory_instance(typeof(MyService), factory)
  51. * .as_type(typeof(IService))
  52. * .build();
  53. * }}}
  54. */
  55. public class Container : Object {
  56. private Catalogue<Type, Registration> registrations;
  57. private Dictionary<Registration, Object> singletons;
  58. public Container() {
  59. this.registrations = new Catalogue<Type, Registration>();
  60. this.singletons = new Dictionary<Registration, Object>();
  61. register_singleton<Container>(s => this);
  62. }
  63. public Registration register_factory_type(Type implementation_type, Factory factory, Lifecycle lifecycle) {
  64. var registration = new Registration(implementation_type, factory, lifecycle);
  65. this.registrations.add(implementation_type, registration);
  66. // Add subsequent aliases added to this registration
  67. registration.alias_added.connect(t => {
  68. this.registrations.add(t, registration);
  69. });
  70. return registration;
  71. }
  72. public Registration register_factory<T>(Factory factory, Lifecycle lifecycle) {
  73. return register_factory_type(typeof(T), factory, lifecycle);
  74. }
  75. public Registration register_type(Type implementation_type, owned FactoryDelegate factory_func, Lifecycle lifecycle) {
  76. var delegate_factory = new DelegateFactory((owned)factory_func);
  77. return register_factory_type(implementation_type, delegate_factory, lifecycle);
  78. }
  79. public Registration register<T>(owned FactoryDelegate factory_func, Lifecycle lifecycle) {
  80. return register_type(typeof(T), (owned)factory_func, lifecycle);
  81. }
  82. public Registration register_transient<T>(owned FactoryDelegate factory_func) {
  83. return register<T>((owned)factory_func, Lifecycle.TRANSIENT);
  84. }
  85. public Registration register_scoped<T>(owned FactoryDelegate factory_func) {
  86. return register<T>((owned)factory_func, Lifecycle.SCOPED);
  87. }
  88. public Registration register_singleton<T>(owned FactoryDelegate factory_func) {
  89. return register<T>((owned)factory_func, Lifecycle.SINGLETON);
  90. }
  91. public bool is_registered(Type type) {
  92. return this.registrations.has(type);
  93. }
  94. public Registration get_registration(Type service_type) throws ContainerError {
  95. try {
  96. return this.registrations.get_any(service_type);
  97. } catch (Error e) {
  98. throw new ContainerError.NOT_REGISTERED(
  99. "Type %s is not registered in the container: %s".printf(service_type.name(), e.message)
  100. );
  101. }
  102. }
  103. /**
  104. * Gets all registrations for a service type.
  105. *
  106. * @param service_type The type to look up
  107. * @return An enumerable of all registrations for the type (may be empty)
  108. */
  109. public Enumerable<Registration> get_registrations(Type service_type) {
  110. return this.registrations.get_or_empty(service_type);
  111. }
  112. /**
  113. * Gets or creates a singleton instance for a registration.
  114. *
  115. * @param registration The registration to get the singleton for
  116. * @param scope The current scope for dependency resolution
  117. * @return The singleton instance
  118. * @throws Error if instance creation fails
  119. */
  120. internal Object get_or_create_singleton(Registration registration, Type requested_type) throws Error {
  121. Object instance;
  122. if (!this.singletons.try_get(registration, out instance)) {
  123. var singleton_scope = new Scope(this, Lifecycle.SINGLETON);
  124. instance = create_with_injection_context(singleton_scope, requested_type, registration);
  125. this.singletons.set(registration, instance);
  126. }
  127. return instance;
  128. }
  129. /**
  130. * Creates a new scope for resolving scoped instances.
  131. *
  132. * @return A new Scope tied to this container
  133. */
  134. public Scope create_scope() {
  135. return new Scope(this, Lifecycle.SCOPED);
  136. }
  137. public Scope create_transient_scope() {
  138. return new Scope(this, Lifecycle.TRANSIENT);
  139. }
  140. }
  141. }