Skip to content

Commit aad7097

Browse files
Implemented SetupContextKind.Reference to allow passing setup context by reference.
1 parent cd724e5 commit aad7097

9 files changed

Lines changed: 110 additions & 8 deletions

File tree

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1504,7 +1504,12 @@ internal enum SetupContextKind
15041504
/// <summary>
15051505
/// Copies referenced instance members into the dependent composition.
15061506
/// </summary>
1507-
Members
1507+
Members,
1508+
1509+
/// <summary>
1510+
/// Passes the setup context by reference and rewrites instance member access through it.
1511+
/// </summary>
1512+
Reference
15081513
}
15091514

15101515
/// <summary>

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1509,7 +1509,12 @@ namespace Pure.DI
15091509
/// <summary>
15101510
/// Copies referenced instance members into the dependent composition.
15111511
/// </summary>
1512-
Members
1512+
Members,
1513+
1514+
/// <summary>
1515+
/// Passes the setup context by reference and rewrites instance member access through it.
1516+
/// </summary>
1517+
Reference
15131518
}
15141519

15151520
/// <summary>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ IReadOnlyCollection<string> CreateRootDescriptions(Root root) =>
137137
var args = composition.ClassArgs
138138
.Where(i => i.Node.Arg?.Source.Kind == ArgKind.Composition)
139139
.Select(arg => arg.Name)
140-
.Concat(composition.SetupContextArgs.Where(arg => arg.Kind == SetupContextKind.Argument).Select(arg => arg.Name));
140+
.Concat(composition.SetupContextArgs.Where(arg => arg.Kind is SetupContextKind.Argument or SetupContextKind.Reference).Select(arg => arg.Name));
141141
code.AppendLine($"/// {(composition.TotalDisposablesCount == 0 ? "" : "using ")}var composition = new {composition.Source.Source.Name.ClassName}({string.Join(", ", args)});");
142142
code.AppendLine($"/// var instance = composition.{formatter.Format(root)};");
143143
code.AppendLine("/// </code>");

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ public bool IsEnabled(CompositionCode composition, ConstructorKind kind) =>
1717
};
1818

1919
private static bool HasSetupContextParameters(CompositionCode composition) =>
20-
composition.SetupContextArgs.Any(arg => arg.Kind == SetupContextKind.Argument);
20+
composition.SetupContextArgs.Any(arg => arg.Kind is SetupContextKind.Argument or SetupContextKind.Reference);
2121

2222
private static bool HasSetupContextArgs(DependencyGraph graph) =>
2323
graph.Source.Bindings.Any(binding =>
24-
binding.Arg is { IsSetupContext: true, SetupContextKind: SetupContextKind.Argument });
24+
binding.Arg is { IsSetupContext: true, SetupContextKind: SetupContextKind.Argument or SetupContextKind.Reference });
2525

2626
private bool IsEnabledInternal(DependencyGraph graph) => (
2727
from entry in graph.Graph.Entries

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void AddComments(CompositionCode composition, Unit unit)
3838
}
3939
}
4040

41-
foreach (var arg in composition.SetupContextArgs.Where(i => i.Kind == SetupContextKind.Argument))
41+
foreach (var arg in composition.SetupContextArgs.Where(i => i.Kind is SetupContextKind.Argument or SetupContextKind.Reference))
4242
{
4343
code.AppendLine($"/// <param name=\"{arg.Name}\">The setup context of type {formatter.FormatRef(arg.Type)}.</param>");
4444
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public CompositionCode Build(CompositionCode composition)
3535
switch (arg.Kind)
3636
{
3737
case SetupContextKind.Argument:
38+
case SetupContextKind.Reference:
3839
var typeName = typeResolver.Resolve(composition.Source.Source, arg.Type);
3940
code.AppendLine($"[{Names.NonSerializedAttributeTypeName}] private readonly {typeName} {arg.Name};");
4041
membersCounter++;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public CompositionCode Build(CompositionCode composition)
2121

2222
var code = composition.Code;
2323
var membersCounter = composition.MembersCount;
24-
var setupContextArgs = composition.SetupContextArgs.Where(arg => arg.Kind == SetupContextKind.Argument).ToArray();
24+
var setupContextArgs = composition.SetupContextArgs.Where(arg => arg.Kind is SetupContextKind.Argument or SetupContextKind.Reference).ToArray();
2525
if (composition.ClassArgs.Length == 0 && setupContextArgs.Length == 0)
2626
{
2727
return composition;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public void AddComments(CompositionCode composition, Root root)
4848
var args = composition.ClassArgs
4949
.Where(i => i.Node.Arg?.Source.Kind == ArgKind.Composition)
5050
.Select(arg => arg.Name)
51-
.Concat(composition.SetupContextArgs.Where(arg => arg.Kind == SetupContextKind.Argument).Select(arg => arg.Name));
51+
.Concat(composition.SetupContextArgs.Where(arg => arg.Kind is SetupContextKind.Argument or SetupContextKind.Reference).Select(arg => arg.Name));
5252
code.AppendLine($"/// {(composition.TotalDisposablesCount == 0 ? "" : "using ")}var composition = new {composition.Source.Source.Name.ClassName}({string.Join(", ", args)});");
5353
code.AppendLine($"/// var instance = composition.{formatter.Format(root)};");
5454
code.AppendLine("/// </code>");

tests/Pure.DI.IntegrationTests/SetupContextTests.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,4 +1566,95 @@ public static void Main()
15661566
result.Warnings.Count.ShouldBe(0, result);
15671567
result.StdOut.ShouldBe(["41", "True", "41", "False", "True", "True"], result);
15681568
}
1569+
1570+
[Fact]
1571+
public async Task ShouldSupportSetupContextReferenceWhenCreatingScope()
1572+
{
1573+
// Given
1574+
1575+
// When
1576+
var result = await """
1577+
using System;
1578+
using Pure.DI;
1579+
1580+
namespace UnityEngine
1581+
{
1582+
// Lightweight test double to avoid Unity dependency
1583+
public class MonoBehaviour {}
1584+
}
1585+
1586+
namespace Sample
1587+
{
1588+
internal partial class BaseComposition
1589+
{
1590+
internal int SettingsValue { get; set; }
1591+
1592+
private void Setup()
1593+
{
1594+
DI.Setup(nameof(BaseComposition), CompositionKind.Internal)
1595+
.Bind<int>().To(_ => SettingsValue);
1596+
}
1597+
}
1598+
1599+
interface IService
1600+
{
1601+
int Value { get; }
1602+
}
1603+
1604+
sealed class Service : IService
1605+
{
1606+
public Service(int value)
1607+
{
1608+
Value = value;
1609+
}
1610+
1611+
public int Value { get; }
1612+
}
1613+
1614+
internal partial class Composition : UnityEngine.MonoBehaviour
1615+
{
1616+
private void Setup()
1617+
{
1618+
DI.Setup(nameof(Composition))
1619+
.DependsOn(nameof(BaseComposition), SetupContextKind.Reference, "baseContext")
1620+
.Bind<IService>().As(Lifetime.Scoped).To<Service>()
1621+
.Root<IService>("Service");
1622+
}
1623+
1624+
public Composition CreateScope() => new(this);
1625+
}
1626+
1627+
public class Program
1628+
{
1629+
public static void Main()
1630+
{
1631+
var baseContext = new BaseComposition
1632+
{
1633+
SettingsValue = 41
1634+
};
1635+
1636+
var composition = new Composition(baseContext);
1637+
1638+
var scope1 = composition.CreateScope();
1639+
var service11 = scope1.Service;
1640+
var service12 = scope1.Service;
1641+
Console.WriteLine(service11.Value);
1642+
Console.WriteLine(service11 == service12);
1643+
1644+
baseContext.SettingsValue = 73;
1645+
var scope2 = composition.CreateScope();
1646+
var service2 = scope2.Service;
1647+
Console.WriteLine(service2.Value);
1648+
Console.WriteLine(service11 == service2);
1649+
}
1650+
}
1651+
}
1652+
""".RunAsync(new Options(LanguageVersion: LanguageVersion.CSharp9));
1653+
1654+
// Then
1655+
result.Success.ShouldBeTrue(result);
1656+
result.Errors.Count.ShouldBe(0, result);
1657+
result.Warnings.Count.ShouldBe(0, result);
1658+
result.StdOut.ShouldBe(["41", "True", "73", "False"], result);
1659+
}
15691660
}

0 commit comments

Comments
 (0)