11using System ;
22using System . Collections . Concurrent ;
3+ using System . Collections . Generic ;
34using System . Collections . ObjectModel ;
45using System . Linq ;
56using System . Linq . Expressions ;
@@ -23,33 +24,17 @@ public sealed class Container : IContainer, IDisposable, IAsyncDisposable
2324 /// Stores the mapping of service types to their implementation types.
2425 /// This enables reflection-based factory compilation and testing visibility.
2526 /// </summary>
26- private readonly ConcurrentDictionary < Type , Type > registrations = new ( ) ;
27+ private readonly ConcurrentDictionary < Type , Registration > registrations = new ( ) ;
2728
28- /// <summary>
29- /// Stores factory delegates for transient service registrations.
30- /// Each resolution will invoke the factory to create a new instance.
31- /// </summary>
32- private readonly ConcurrentDictionary < Type , Func < Container , object > > transients = new ( ) ;
33-
34- /// <summary>
35- /// Stores lazy-initialized singleton instances for singleton service registrations.
36- /// The instance is created once and reused for all subsequent resolutions.
37- /// </summary>
38- private readonly ConcurrentDictionary < Type , Lazy < object > > singletons = new ( ) ;
3929
4030 // ┌─────────────────────────────────────────────────────────────────────────────┐
4131 // │ Internal Properties │
4232 // └─────────────────────────────────────────────────────────────────────────────┘
4333
4434 /// <summary>
45- /// Gets a read-only view of all registered service-to-implementation type mappings.
46- /// </summary>
47- internal ReadOnlyDictionary < Type , Type > Registrations => new ( registrations ) ;
48-
49- /// <summary>
50- /// Gets a read-only view of all resolved singleton instances.
35+ /// Gets a read-only view of all registered services and their corresponding registrations.
5136 /// </summary>
52- internal ReadOnlyDictionary < Type , object > Singletons => new ( singletons . ToDictionary ( kvp => kvp . Key , kvp => kvp . Value . Value ) ) ;
37+ internal ReadOnlyDictionary < Type , Registration > Registrations => registrations . AsReadOnly ( ) ;
5338
5439 // ┌─────────────────────────────────────────────────────────────────────────────┐
5540 // │ Public Methods │
@@ -58,106 +43,68 @@ public sealed class Container : IContainer, IDisposable, IAsyncDisposable
5843 /// <inheritdoc/>
5944 public void Dispose ( )
6045 {
61- foreach ( Lazy < object > lazy in singletons . Values )
46+ foreach ( Registration registration in registrations . Values . Where ( r => r . DisposeWithContainer . HasValue && r . DisposeWithContainer . Value ) )
6247 {
63- switch ( lazy . Value )
48+ if ( registration . Singleton ? . IsValueCreated == true )
6449 {
65- case IAsyncDisposable asyncDisposable :
66- asyncDisposable . DisposeAsync ( ) . AsTask ( ) . GetAwaiter ( ) . GetResult ( ) ;
67- break ;
68- case IDisposable disposable :
69- disposable . Dispose ( ) ;
70- break ;
50+ switch ( registration . Singleton . Value )
51+ {
52+ case IAsyncDisposable asyncDisposable :
53+ asyncDisposable . DisposeAsync ( ) . AsTask ( ) . GetAwaiter ( ) . GetResult ( ) ;
54+ break ;
55+ case IDisposable disposable :
56+ disposable . Dispose ( ) ;
57+ break ;
58+ }
7159 }
7260 }
7361 }
7462
7563 /// <inheritdoc/>
7664 public async ValueTask DisposeAsync ( )
7765 {
78- foreach ( Lazy < object > lazy in singletons . Values )
66+ foreach ( Registration registration in registrations . Values . Where ( r => r . DisposeWithContainer . HasValue && r . DisposeWithContainer . Value ) )
7967 {
80- switch ( lazy . Value )
68+ if ( registration . Singleton ? . IsValueCreated == true )
8169 {
82- case IAsyncDisposable asyncDisposable :
83- await asyncDisposable . DisposeAsync ( ) . ConfigureAwait ( false ) ;
84- break ;
85- case IDisposable disposable :
86- disposable . Dispose ( ) ;
87- break ;
70+ switch ( registration . Singleton . Value )
71+ {
72+ case IAsyncDisposable asyncDisposable :
73+ await asyncDisposable . DisposeAsync ( ) . ConfigureAwait ( false ) ;
74+ break ;
75+ case IDisposable disposable :
76+ disposable . Dispose ( ) ;
77+ break ;
78+ }
8879 }
8980 }
9081 }
9182
9283 /// <inheritdoc/>
93- public void RegisterTransient < TService , TImplementation > ( )
94- where TImplementation : TService
95- => transients [ typeof ( TService ) ] = CompileFactory ( typeof ( TImplementation ) ) ;
96-
97- /// <inheritdoc/>
98- public void RegisterTransient ( Type serviceType , Type implType )
84+ public void RegisterTransient ( Type serviceType , Type implementationType )
9985 {
10086 ArgumentNullException . ThrowIfNull ( serviceType , nameof ( serviceType ) ) ;
101- ArgumentNullException . ThrowIfNull ( implType , nameof ( implType ) ) ;
87+ ArgumentNullException . ThrowIfNull ( implementationType , nameof ( implementationType ) ) ;
10288
103- transients [ serviceType ] = CompileFactory ( implType ) ;
89+ registrations [ serviceType ] = new Registration ( CompileFactory ( implementationType ) , null , null ) ;
10490 }
10591
10692 /// <inheritdoc/>
107- public void RegisterTransient < TService > ( Func < Container , TService > factory )
108- where TService : notnull
109- => RegisterTransient ( typeof ( TService ) , c => factory ( c ) ! ) ;
110-
111- /// <inheritdoc/>
112- public void RegisterTransient ( Type serviceType , Func < Container , object > factory )
113- {
114- ArgumentNullException . ThrowIfNull ( serviceType , nameof ( serviceType ) ) ;
115- ArgumentNullException . ThrowIfNull ( factory , nameof ( factory ) ) ;
116-
117- transients [ serviceType ] = c => factory ( c ) ! ;
118- }
119-
120- /// <inheritdoc/>
121- public void RegisterSingleton < TService , TImplementation > ( )
122- where TImplementation : TService
123- => RegisterSingleton ( typeof ( TService ) , typeof ( TImplementation ) ) ;
124-
125- /// <inheritdoc/>
126- public void RegisterSingleton ( Type serviceType , Type implType )
93+ public void RegisterSingleton ( Type serviceType , Type implType , bool disposeWithContainer = true )
12794 {
12895 ArgumentNullException . ThrowIfNull ( serviceType , nameof ( serviceType ) ) ;
12996 ArgumentNullException . ThrowIfNull ( implType , nameof ( implType ) ) ;
13097
131- singletons [ serviceType ] = new Lazy < object > ( ( ) => CompileFactory ( implType ) ( this ) ) ;
132- }
133-
134- /// <inheritdoc/>
135- public void RegisterSingleton < TService > ( Func < Container , TService > factory )
136- where TService : notnull
137- => RegisterSingleton ( typeof ( TService ) , c => factory ( c ) ! ) ;
138-
139- /// <inheritdoc/>
140- public void RegisterSingleton ( Type serviceType , Func < Container , object > factory )
141- {
142- ArgumentNullException . ThrowIfNull ( serviceType , nameof ( serviceType ) ) ;
143- ArgumentNullException . ThrowIfNull ( factory , nameof ( factory ) ) ;
144-
145- singletons [ serviceType ] = new Lazy < object > ( ( ) => factory ( this ) ! ) ;
98+ registrations [ serviceType ] = new Registration ( null , new Lazy < object > ( ( ) => CompileFactory ( implType ) ( this ) ) , disposeWithContainer ) ;
14699 }
147100
148101 /// <inheritdoc/>
149- public void RegisterInstance < TService > ( TService instance )
150- where TService : notnull
151- => RegisterInstance ( typeof ( TService ) , instance ) ;
152-
153- /// <inheritdoc/>
154- public void RegisterInstance ( Type serviceType , object instance )
102+ public void RegisterInstance ( Type serviceType , object instance , bool disposeWithContainer = true )
155103 {
156104 ArgumentNullException . ThrowIfNull ( serviceType , nameof ( serviceType ) ) ;
157105 ArgumentNullException . ThrowIfNull ( instance , nameof ( instance ) ) ;
158106
159- registrations [ serviceType ] = instance . GetType ( ) ;
160- singletons [ serviceType ] = new Lazy < object > ( ( ) => instance ) ;
107+ registrations [ serviceType ] = new Registration ( null , new Lazy < object > ( ( ) => instance ) , disposeWithContainer ) ;
161108 }
162109
163110 /// <inheritdoc/>
@@ -170,24 +117,25 @@ public object Resolve(Type serviceType)
170117 {
171118 ArgumentNullException . ThrowIfNull ( serviceType , nameof ( serviceType ) ) ;
172119
173- if ( singletons . TryGetValue ( serviceType , out var lazy ) )
120+ if ( registrations . TryGetValue ( serviceType , out Registration registration ) )
174121 {
175- return lazy . Value ;
176- }
177-
178- if ( transients . TryGetValue ( serviceType , out var factory ) )
179- {
180- return factory ( this ) ;
122+ if ( registration . Singleton is not null )
123+ {
124+ return registration . Singleton . Value ;
125+ }
126+ else if ( registration . Factory is not null )
127+ {
128+ return registration . Factory ( this ) ;
129+ }
130+ else
131+ {
132+ throw new InvalidOperationException ( $ "No factory or singleton instance found for service type: { serviceType . FullName } ") ;
133+ }
181134 }
182135
183136 throw new InvalidOperationException ( $ "Service not registered: { serviceType . FullName } ") ;
184137 }
185138
186- /// <inheritdoc/>
187- public TService New < TService > ( )
188- where TService : notnull
189- => ( TService ) New ( typeof ( TService ) ) ;
190-
191139 /// <inheritdoc/>
192140 public object New ( Type implType )
193141 {
0 commit comments