@@ -8,8 +8,7 @@ namespace Pure.DI.Core.Code.Parts;
88sealed class ScopeConstructorBuilder (
99 ILocks locks ,
1010 IConstructors constructors ,
11- ICodeNameProvider codeNameProvider ,
12- ITypeResolver typeResolver )
11+ ICodeNameProvider codeNameProvider )
1312 : IClassPartBuilder
1413{
1514 public ClassPart Part => ClassPart . ScopeConstructor ;
@@ -23,10 +22,32 @@ public CompositionCode Build(CompositionCode composition)
2322 }
2423
2524 return composition . Source . Source . Hints . ScopeStrategy == ScopeStrategy . StateObject
26- ? BuildStateObjectScope ( composition )
25+ ? BuildStateObjectScopeFactory ( composition )
2726 : BuildCompositionInstanceScope ( composition ) ;
2827 }
2928
29+ private CompositionCode BuildStateObjectScopeFactory ( CompositionCode composition )
30+ {
31+ var code = composition . Code ;
32+ var membersCounter = composition . MembersCount ;
33+ var isCommentsEnabled = composition . Source . Source . Hints . IsCommentsEnabled ;
34+ if ( isCommentsEnabled )
35+ {
36+ code . AppendLine ( "/// <summary>" ) ;
37+ code . AppendLine ( "/// Creates a new scope represented by a dedicated state object." ) ;
38+ code . AppendLine ( "/// </summary>" ) ;
39+ }
40+
41+ code . AppendLine ( "public ScopeHandle CreateScope()" ) ;
42+ using ( code . CreateBlock ( ) )
43+ {
44+ code . AppendLine ( "return new ScopeHandle(this, isRootScope: false);" ) ;
45+ }
46+
47+ membersCounter ++ ;
48+ return composition with { MembersCount = membersCounter } ;
49+ }
50+
3051 private CompositionCode BuildCompositionInstanceScope ( CompositionCode composition )
3152 {
3253 if ( ! constructors . IsEnabled ( composition , ConstructorKind . Scope ) )
@@ -109,211 +130,6 @@ private CompositionCode BuildCompositionInstanceScope(CompositionCode compositio
109130 return composition with { MembersCount = membersCounter } ;
110131 }
111132
112- private CompositionCode BuildStateObjectScope ( CompositionCode composition )
113- {
114- var code = composition . Code ;
115- var membersCounter = composition . MembersCount ;
116- var hints = composition . Source . Source . Hints ;
117- var isCommentsEnabled = hints . IsCommentsEnabled ;
118- var hasScopedDisposables = composition . DisposablesScopedCount > 0 ;
119- var hasAsyncDisposables = composition . AsyncDisposableCount > 0 ;
120- var scopedFields = composition . Singletons
121- . Where ( i => i . Node . ActualLifetime == Lifetime . Scoped )
122- . ToImmutableArray ( ) ;
123- var nullable = composition . Compilation . Options . NullableContextOptions == NullableContextOptions . Disable ? "" : "?" ;
124- var compositionTypeName = composition . Source . Source . Name . ClassName ;
125-
126- if ( isCommentsEnabled )
127- {
128- code . AppendLine ( "/// <summary>" ) ;
129- code . AppendLine ( "/// Creates a new scope represented by a dedicated state object." ) ;
130- code . AppendLine ( "/// </summary>" ) ;
131- }
132-
133- code . AppendLine ( "public ScopeHandle CreateScope()" ) ;
134- using ( code . CreateBlock ( ) )
135- {
136- code . AppendLine ( "return new ScopeHandle(this, isRootScope: false);" ) ;
137- }
138-
139- code . AppendLine ( ) ;
140- if ( isCommentsEnabled )
141- {
142- code . AppendLine ( "/// <summary>" ) ;
143- code . AppendLine ( "/// Represents a scope state and tracks scoped instances and their disposal." ) ;
144- code . AppendLine ( "/// </summary>" ) ;
145- }
146-
147- code . AppendLine ( $ "public sealed class ScopeHandle: { Names . IDisposableTypeName } ") ;
148- using ( code . CreateBlock ( ) )
149- {
150- code . AppendLine ( $ "[{ Names . NonSerializedAttributeTypeName } ] private readonly { compositionTypeName } _composition;") ;
151- code . AppendLine ( $ "[{ Names . NonSerializedAttributeTypeName } ] private readonly ScopeHandle{ nullable } _previousScope;") ;
152- code . AppendLine ( $ "[{ Names . NonSerializedAttributeTypeName } ] private readonly bool _isRootScope;") ;
153- code . AppendLine ( $ "[{ Names . NonSerializedAttributeTypeName } ] private bool _isDisposed;") ;
154- if ( hasScopedDisposables )
155- {
156- code . AppendLine ( $ "[{ Names . NonSerializedAttributeTypeName } ] internal object[] { Names . DisposablesFieldName } ;") ;
157- code . AppendLine ( $ "[{ Names . NonSerializedAttributeTypeName } ] internal int { Names . DisposeIndexFieldName } ;") ;
158- }
159-
160- if ( scopedFields . Length > 0 )
161- {
162- code . AppendLine ( ) ;
163- }
164-
165- foreach ( var scopedField in scopedFields )
166- {
167- if ( scopedField . InstanceType . IsValueType )
168- {
169- code . AppendLine ( $ "[{ Names . NonSerializedAttributeTypeName } ] internal { typeResolver . Resolve ( composition . Source . Source , scopedField . InstanceType ) } { scopedField . Name } ;") ;
170- code . AppendLine ( $ "[{ Names . NonSerializedAttributeTypeName } ] internal bool { scopedField . Name } { Names . CreatedValueNameSuffix } ;") ;
171- }
172- else
173- {
174- code . AppendLine ( $ "[{ Names . NonSerializedAttributeTypeName } ] internal { typeResolver . Resolve ( composition . Source . Source , scopedField . InstanceType ) } { nullable } { scopedField . Name } ;") ;
175- }
176- }
177-
178- code . AppendLine ( ) ;
179- code . AppendLine ( $ "internal ScopeHandle({ compositionTypeName } composition, bool isRootScope)") ;
180- using ( code . CreateBlock ( ) )
181- {
182- const string compositionLocalName = "compositionChecked" ;
183- code . AppendLine ( $ "var { compositionLocalName } = composition ?? throw new { Names . SystemNamespace } ArgumentNullException(nameof(composition));") ;
184- code . AppendLine ( "_composition = compositionChecked;" ) ;
185- code . AppendLine ( "_isRootScope = isRootScope;" ) ;
186- if ( hasScopedDisposables )
187- {
188- code . AppendLine ( $ "{ Names . DisposablesFieldName } = new object[{ composition . DisposablesScopedCount . ToString ( ) } ];") ;
189- }
190-
191- code . AppendLine ( "if (!isRootScope)" ) ;
192- using ( code . CreateBlock ( ) )
193- {
194- code . AppendLine ( $ "_previousScope = { compositionTypeName } .{ Names . CurrentScopeFieldName } ;") ;
195- code . AppendLine ( $ "{ compositionTypeName } .{ Names . CurrentScopeFieldName } = this;") ;
196- }
197- }
198-
199- code . AppendLine ( ) ;
200- if ( isCommentsEnabled )
201- {
202- code . AppendLine ( "/// <summary>" ) ;
203- code . AppendLine ( "/// Disposes all tracked scoped disposable instances and closes this scope." ) ;
204- code . AppendLine ( "/// </summary>" ) ;
205- }
206-
207- code . AppendLine ( "public void Dispose()" ) ;
208- using ( code . CreateBlock ( ) )
209- {
210- code . AppendLine ( "if (_isDisposed)" ) ;
211- using ( code . CreateBlock ( ) )
212- {
213- code . AppendLine ( "return;" ) ;
214- }
215-
216- code . AppendLine ( "_isDisposed = true;" ) ;
217- code . AppendLine ( $ "if (!_isRootScope && global::System.Object.ReferenceEquals({ compositionTypeName } .{ Names . CurrentScopeFieldName } , this))") ;
218- using ( code . CreateBlock ( ) )
219- {
220- code . AppendLine ( $ "{ compositionTypeName } .{ Names . CurrentScopeFieldName } = _previousScope;") ;
221- }
222-
223- if ( hasScopedDisposables )
224- {
225- code . AppendLine ( ) ;
226- code . AppendLine ( $ "var disposeIndex = { Names . DisposeIndexFieldName } ;") ;
227- code . AppendLine ( $ "{ Names . DisposeIndexFieldName } = 0;") ;
228- code . AppendLine ( $ "var disposables = { Names . DisposablesFieldName } ;") ;
229- code . AppendLine ( $ "{ Names . DisposablesFieldName } = new object[{ composition . DisposablesScopedCount . ToString ( ) } ];") ;
230- code . AppendLine ( "while (disposeIndex-- > 0)" ) ;
231- using ( code . CreateBlock ( ) )
232- {
233- code . AppendLine ( "switch (disposables[disposeIndex])" ) ;
234- using ( code . CreateBlock ( ) )
235- {
236- code . AppendLine ( $ "case { Names . IDisposableTypeName } disposableInstance:") ;
237- using ( code . Indent ( ) )
238- {
239- code . AppendLine ( "try" ) ;
240- using ( code . CreateBlock ( ) )
241- {
242- code . AppendLine ( "disposableInstance.Dispose();" ) ;
243- }
244-
245- code . AppendLine ( $ "catch ({ Names . ExceptionTypeName } exception)") ;
246- using ( code . CreateBlock ( ) )
247- {
248- code . AppendLine ( "_composition.OnDisposeException(disposableInstance, exception);" ) ;
249- }
250-
251- code . AppendLine ( "break;" ) ;
252- }
253-
254- if ( hasAsyncDisposables )
255- {
256- code . AppendLine ( ) ;
257- code . AppendLine ( $ "case { Names . IAsyncDisposableTypeName } asyncDisposableInstance:") ;
258- using ( code . Indent ( ) )
259- {
260- code . AppendLine ( "try" ) ;
261- using ( code . CreateBlock ( ) )
262- {
263- code . AppendLine ( "var valueTask = asyncDisposableInstance.DisposeAsync();" ) ;
264- code . AppendLine ( "if (!valueTask.IsCompleted)" ) ;
265- using ( code . CreateBlock ( ) )
266- {
267- code . AppendLine ( "valueTask.AsTask().Wait();" ) ;
268- }
269- }
270-
271- code . AppendLine ( $ "catch ({ Names . ExceptionTypeName } exception)") ;
272- using ( code . CreateBlock ( ) )
273- {
274- code . AppendLine ( "_composition.OnDisposeAsyncException(asyncDisposableInstance, exception);" ) ;
275- }
276-
277- code . AppendLine ( "break;" ) ;
278- }
279- }
280- }
281- }
282- }
283-
284- if ( scopedFields . Length > 0 )
285- {
286- code . AppendLine ( ) ;
287- }
288-
289- foreach ( var scopedField in scopedFields )
290- {
291- if ( scopedField . InstanceType . IsValueType )
292- {
293- code . AppendLine ( $ "{ scopedField . Name } = default({ typeResolver . Resolve ( composition . Source . Source , scopedField . InstanceType ) } );") ;
294- code . AppendLine ( $ "{ scopedField . Name } { Names . CreatedValueNameSuffix } = false;") ;
295- }
296- else
297- {
298- code . AppendLine ( $ "{ scopedField . Name } = null;") ;
299- }
300- }
301- }
302-
303- if ( hints . IsResolveEnabled )
304- {
305- code . AppendLine ( ) ;
306- code . AppendLine ( $ "public T { hints . ResolveMethodName } <T>() => _composition.{ hints . ResolveMethodName } <T>();") ;
307- code . AppendLine ( $ "public T { hints . ResolveByTagMethodName } <T>(object{ nullable } tag) => _composition.{ hints . ResolveByTagMethodName } <T>(tag);") ;
308- code . AppendLine ( $ "public object { hints . ObjectResolveMethodName } ({ Names . SystemNamespace } Type type) => _composition.{ hints . ObjectResolveMethodName } (type);") ;
309- code . AppendLine ( $ "public object { hints . ObjectResolveByTagMethodName } ({ Names . SystemNamespace } Type type, object{ nullable } tag) => _composition.{ hints . ObjectResolveByTagMethodName } (type, tag);") ;
310- }
311- }
312-
313- membersCounter += 2 ;
314- return composition with { MembersCount = membersCounter } ;
315- }
316-
317133 private static IReadOnlyCollection < string > GetSetupContextMembersToCopy ( CompositionCode composition )
318134 {
319135 var memberNames = new HashSet < string > ( StringComparer . Ordinal ) ;
0 commit comments