Skip to content

Commit ae4d206

Browse files
4
1 parent e281f4c commit ae4d206

4 files changed

Lines changed: 233 additions & 209 deletions

File tree

src/Pure.DI.Core/Core/Code/Parts/ClassPart.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ enum ClassPart
88
ParameterizedConstructor,
99
DefaultConstructor,
1010
ScopeConstructor,
11+
ScopeHandle,
1112
RootMethods,
1213
ApiMembers,
1314
DisposeMethod,

src/Pure.DI.Core/Core/Code/Parts/ScopeConstructorBuilder.cs

Lines changed: 24 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ namespace Pure.DI.Core.Code.Parts;
88
sealed 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

Comments
 (0)