Skip to content

Commit 5e8dab0

Browse files
#138 Make anonymous roots lightweight
1 parent 45b2a72 commit 5e8dab0

10 files changed

Lines changed: 111 additions & 19 deletions

File tree

src/Pure.DI.Core/Components/Api.g.cs

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,22 @@ namespace System
1010
internal delegate TResult Func<out TResult>();
1111
#endif
1212
#if NET20 || NET35
13-
internal delegate TResult Func<in T, out TResult>(T arg);
14-
internal delegate TResult Func<in T, in T1, out TResult>(T arg, T1 arg1);
15-
internal delegate TResult Func<in T, in T1, in T2, out TResult>(T arg, T1 arg1, T2 arg2);
16-
internal delegate TResult Func<in T, in T1, in T2, in T3, out TResult>(T arg, T1 arg1, T2 arg2, T3 arg3);
17-
internal delegate TResult Func<in T, in T1, in T2, in T3, in T4, out TResult>(T arg, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
18-
internal delegate TResult Func<in T, in T1, in T2, in T3, in T4, in T5, out TResult>(T arg, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
19-
internal delegate TResult Func<in T, in T1, in T2, in T3, in T4, in T5, in T6, out TResult>(T arg, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
20-
internal delegate TResult Func<in T, in T1, in T2, in T3, in T4, in T5, in T6, in T7, out TResult>(T arg, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
13+
internal delegate TResult Func<in T1, out TResult>(T1 arg1);
14+
internal delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
15+
internal delegate TResult Func<in T1, in T2, in T3, out TResult>(T1 arg1, T2 arg2, T3 arg3);
16+
internal delegate TResult Func<in T1, in T2, in T3, in T4, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4);
17+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
18+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
19+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
20+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
21+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
22+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
23+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
24+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
25+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
26+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
27+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
28+
internal delegate TResult Func<in T1, in T2, in T3, in T4, in T5, in T6, in T7, in T8, in T9, in T10, in T11, in T12, in T13, in T14, in T15, in T16, out TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
2129
#endif
2230
}
2331
#endif
@@ -8310,6 +8318,9 @@ internal interface IResolver<TComposite, out T>
83108318
T ResolveByTag(TComposite composite, object tag);
83118319
}
83128320

8321+
/// <summary>
8322+
/// Lightweight composition root. Does not create a separate composition object for instance creation, uses a common one for all lightweight roots and a delegate to create the type instance.
8323+
/// </summary>
83138324
internal class LightweightRoot { }
83148325

83158326
/// <summary>

src/Pure.DI.Core/Components/Api.g.tt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ namespace System
2222
internal delegate TResult Func<out TResult>();
2323
#endif
2424
#if NET20 || NET35
25-
<#for(var i = 0; i < baseCount; i ++)
25+
<#for(var i = 1; i <= 16; i ++)
2626
{
27-
var typeArgs = string.Join(", ", GetSuffixes(0, i).Select(suffix => $"in T{suffix}"));
28-
var args = string.Join(", ", GetSuffixes(0, i).Select(suffix => $"T{suffix} arg{suffix}"));
27+
var typeArgs = string.Join(", ", GetSuffixes(1, i).Select(suffix => $"in T{suffix}"));
28+
var args = string.Join(", ", GetSuffixes(1, i).Select(suffix => $"T{suffix} arg{suffix}"));
2929
#>
3030
internal delegate TResult Func<<#=typeArgs#>, out TResult>(<#=args#>);
3131
<#
@@ -3580,6 +3580,9 @@ var typeArgs = string.Join(", ", GetSuffixes(1, i + 1).Select(suffix => $"T{suff
35803580
T ResolveByTag(TComposite composite, object tag);
35813581
}
35823582

3583+
/// <summary>
3584+
/// Lightweight composition root. Does not create a separate composition object for instance creation, uses a common one for all lightweight roots and a delegate to create the type instance.
3585+
/// </summary>
35833586
internal class LightweightRoot { }
35843587

35853588
/// <summary>

src/Pure.DI.Core/Core/Code/ResolversBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sealed class ResolversBuilder(ITypeResolver typeResolver)
77
{
88
public IEnumerable<ResolverInfo> Build(RootsContext ctx) =>
99
ctx.Roots
10-
.Where(i => i.RootArgs.IsEmpty && !i.Source.IsLightweightRootMethod)
10+
.Where(i => i.RootArgs.IsEmpty && i.Source.LightweightKind is not LightweightKind.TransientComposition)
1111
.Where(i => !i.Injection.Type.IsRefLikeType)
1212
.Where(i => !ReferenceEquals(i.Injection.Tag, MdTag.ContextTag))
1313
.Where(i => typeResolver.Resolve(ctx.Setup, i.Injection.Type).TypeArgs.Count == 0)

src/Pure.DI.Core/Core/Code/VariableNameProvider.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ public string GetLocalUniqueVariableName(string baseName) =>
2424
uniqueNameProvider.GetUniqueName($"{Names.LocalVariablePrefix}{ToTitleCase(baseName)}{Names.Salt}");
2525

2626
public string GetUniqueRootName(string name, ITypeSymbol rootType) =>
27-
string.IsNullOrWhiteSpace(name)
28-
? uniqueNameProvider.GetUniqueName(ToTitleCase(rootType.Name))
29-
: name;
27+
uniqueNameProvider.GetUniqueName(string.IsNullOrWhiteSpace(name) ? ToTitleCase(rootType.Name) : name);
3028

3129
private static string GetVariableName(string prefix, string baseName, int id) =>
3230
$"{prefix}{ToTitleCase(baseName)}{Names.Salt}{(id != 0 ? id.ToString() : "")}";

src/Pure.DI.Core/Core/LifetimesValidator.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ public bool Validate(DependencyGraph dependencyGraph)
1616
}
1717

1818
var errors = new HashSet<object>();
19-
var graph = dependencyGraph.Graph;
2019
foreach (var root in dependencyGraph.Roots)
2120
{
2221
graphWalker.Walk(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Pure.DI.Core.Models;
2+
3+
public enum LightweightKind
4+
{
5+
None,
6+
TransientRoot,
7+
TransientComposition
8+
}

src/Pure.DI.Core/Core/Models/MdRoot.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ record MdRoot(
1313
ITypeSymbol RootContractType,
1414
bool IsBuilder,
1515
ImmutableArray<MdRoot> BuilderRoots = default,
16-
bool IsLightweightRootMethod = false)
16+
LightweightKind LightweightKind = LightweightKind.None)
1717
{
1818
public override string ToString() => $"Root<{RootType}>(\"{Name}\", {Tag.ToString()})";
1919
}

src/Pure.DI.Core/Core/RootDependencyNodeBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public IEnumerable<DependencyNode> Build(DependencyNodeBuildContext ctx)
5757
rootType,
5858
false,
5959
ImmutableArray<MdRoot>.Empty,
60-
IsLightweightRootMethod: true);
60+
LightweightKind: LightweightKind.TransientComposition);
6161

6262
var binding = bindingsFactory.CreateLightweightRootBinding(setup, root);
6363

src/Pure.DI.Core/Core/RootValidator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public bool Validate(CompositionCode composition)
1616
}
1717

1818
var invalidRoots = composition.PublicRoots
19-
.Where(root => root.Source is { IsBuilder: false, IsLightweightRootMethod: false })
19+
.Where(root => root.Source is { IsBuilder: false, LightweightKind: not LightweightKind.TransientComposition })
2020
.Where(root => !root.RootArgs.IsDefaultOrEmpty && root.TypeDescription.TypeArgs.Count == 0)
2121
.GroupBy(root => root.Node.Binding.Id)
2222
.Select(root => root.First());

tests/Pure.DI.IntegrationTests/LightweightRootsTests.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,77 @@ public static void Main()
126126
result.Success.ShouldBeTrue(result);
127127
result.StdOut.ShouldBe(["Initialize 1 Abc"], result);
128128
}
129+
130+
[Fact]
131+
public async Task ShouldSupportSeveralLightweightRoots()
132+
{
133+
// Given
134+
135+
// When
136+
var result = await """
137+
using System;
138+
using Pure.DI;
139+
140+
namespace Sample
141+
{
142+
interface IDependency {}
143+
144+
class Dependency: IDependency
145+
{
146+
}
147+
148+
interface IService
149+
{
150+
IDependency? Dep { get; }
151+
}
152+
153+
class Service: IService
154+
{
155+
[Ordinal(1)]
156+
internal void Initialize([Tag(374)] string depName)
157+
{
158+
Console.WriteLine($"Initialize 1 {depName}");
159+
}
160+
161+
[Ordinal(0)]
162+
public IDependency? Dep { get; set; }
163+
}
164+
165+
class Xyz
166+
{
167+
public Xyz()
168+
{
169+
Console.WriteLine("Xyz");
170+
}
171+
}
172+
173+
static class Setup
174+
{
175+
private static void SetupComposition()
176+
{
177+
DI.Setup("Composition")
178+
.Bind(374).To(_ => "Abc")
179+
.Bind().As(Lifetime.PerResolve).To<Dependency>()
180+
.Root<Service>("Root", kind: RootKinds.Light)
181+
.Root<Xyz>("Xyz", kind: RootKinds.Light);
182+
}
183+
}
184+
185+
public class Program
186+
{
187+
public static void Main()
188+
{
189+
var composition = new Composition();
190+
var service1 = composition.Root;
191+
var service2 = composition.Resolve<Service>();
192+
var xyz = composition.Xyz;
193+
}
194+
}
195+
}
196+
""".RunAsync();
197+
198+
// Then
199+
result.Success.ShouldBeTrue(result);
200+
result.StdOut.ShouldBe(["Initialize 1 Abc", "Initialize 1 Abc", "Xyz"], result);
201+
}
129202
}

0 commit comments

Comments
 (0)