Skip to content

Commit

Permalink
By default, assigns a PerResolve lifetime to the Func
Browse files Browse the repository at this point in the history
  • Loading branch information
NikolayPianikov committed Aug 28, 2024
1 parent c5e3790 commit 9df0cec
Show file tree
Hide file tree
Showing 12 changed files with 43 additions and 40 deletions.
2 changes: 1 addition & 1 deletion benchmarks/Pure.DI.Benchmarks/Benchmarks/Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Pure.DI.Benchmarks.Benchmarks;
public partial class Array : BenchmarkBase
{
private static void SetupDI() =>
DI.Setup(nameof(Array))
DI.Setup()
.Bind().To<Service1>()
.Bind().To<Service2Array>()
.Bind().To<Service3>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,5 @@ void Setup() =>
DI.Setup("Default", CompositionKind.Global)
.Hint(Hint.ThreadSafe, "Off")
.Hint(Hint.ToString, "On")
.Hint(Hint.FormatCode, "On")
.Bind<Func<TT>>()
.As(Lifetime.PerBlock)
.To(ctx => new Func<TT>(() =>
{
ctx.Inject<TT>(ctx.Tag, out var value);
return value;
}));
.Hint(Hint.FormatCode, "On");
}
2 changes: 1 addition & 1 deletion benchmarks/Pure.DI.Benchmarks/Benchmarks/Enum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Pure.DI.Benchmarks.Benchmarks;
public partial class Enum : BenchmarkBase
{
private static void SetupDI() =>
DI.Setup(nameof(Enum))
DI.Setup()
.Bind().To<Service1>()
.Bind().To<Service2Enum>()
.Bind().To<Service3>()
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/Pure.DI.Benchmarks/Benchmarks/Func.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace Pure.DI.Benchmarks.Benchmarks;
public partial class Func : BenchmarkBase
{
private static void SetupDI() =>
DI.Setup(nameof(Func))
DI.Setup()
.Bind().To<Service1>()
.Bind().To<Service2Func>()
.Bind().To<Service3>()
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/Pure.DI.Benchmarks/Benchmarks/Singleton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Pure.DI.Benchmarks.Benchmarks;
public partial class Singleton : BenchmarkBase
{
private static void SetupDI() =>
DI.Setup(nameof(Singleton))
DI.Setup()
.Bind().As(Lifetime.Scoped).To<Service1>()
.Bind().To<Service2>()
.Bind().To<Service3>()
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/Pure.DI.Benchmarks/Benchmarks/Transient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Pure.DI.Benchmarks.Benchmarks;
public partial class Transient : BenchmarkBase
{
private static void SetupDI() =>
DI.Setup(nameof(Transient))
DI.Setup()
.Bind().To<Service1>()
.Bind().To<Service2>()
.Bind().To<Service3>()
Expand Down
8 changes: 2 additions & 6 deletions src/Pure.DI.Core/Core/Code/BuildTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,9 @@ public string OnInjected(BuildContext ctx, Variable variable)
&& ctx.DependencyGraph.Source.SemanticModel.Compilation.Options.NullableContextOptions != NullableContextOptions.Disable
&& (variable.HasCycle || variable.Node.Lifetime is Lifetime.Singleton or Lifetime.Scoped or Lifetime.PerResolve);

if (skipNotNullCheck)
if (skipNotNullCheck && (variable.HasCycle || variable.Node.Lifetime is Lifetime.Singleton or Lifetime.Scoped or Lifetime.PerResolve))
{
variableCode = variable.Node.Lifetime switch
{
Lifetime.Singleton or Lifetime.PerResolve or Lifetime.Scoped => $"{variableCode}!",
_ => variableCode
};
variableCode = $"{variableCode}!";
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/Pure.DI.Core/Core/Code/FactoryCodeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ public void Build(BuildContext ctx, in DpFactory factory)
new FactoryValidator(factory).Validate(lambda);
SyntaxNode syntaxNode = lambda.Block is not null ? lambda.Block : SyntaxFactory.ExpressionStatement((ExpressionSyntax)lambda.Body);
var lines = new List<TextLine>();
if (!variable.IsDeclared && variable.IsLazy)
{
ctx.Code.AppendLine($"var {variable.VariableName} = default({ctx.BuildTools.GetDeclaration(variable)});");
variable.IsDeclared = true;
}

if (syntaxNode is BlockSyntax curBlock)
{
if (!variable.IsDeclared)
Expand Down
2 changes: 1 addition & 1 deletion src/Pure.DI.Core/Core/Code/Variable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal record Variable(

public Block ParentBlock => this.GetPath().OfType<Block>().First();

public bool IsDeclared { get; } = Node.Lifetime is not Lifetime.Transient and not Lifetime.PerBlock || Node.Arg is not null;
public bool IsDeclared { get; set; } = Node.Lifetime is not Lifetime.Transient and not Lifetime.PerBlock || Node.Arg is not null;

public string VariableDeclarationName =>
string.IsNullOrEmpty(NameOverride)
Expand Down
38 changes: 23 additions & 15 deletions src/Pure.DI.Core/Core/Code/VariablesBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ public Block Build(
blockMap,
rootNode,
rootInjection,
ref transientId,
false));
ref transientId));

var blocks = new Stack<Block>();
blocks.Push(rootBlock);
Expand Down Expand Up @@ -59,13 +58,13 @@ public Block Build(
}
}

var pathIds = new HashSet<int>();
var path = new Dictionary<int, Variable>();
ICollection<Accumulator>? accumulators = default;
var isRoot = true;
foreach (var pathItem in currentStatement.GetPath())
{
var pathVar = pathItem.Current;
pathIds.Add(pathVar.Node.Binding.Id);
path[pathVar.Node.Binding.Id] = pathItem.Current;
if (!pathVar.IsLazy)
{
continue;
Expand Down Expand Up @@ -103,8 +102,8 @@ public Block Build(
{
continue;
}
var hasCycle = pathIds.Contains(depNode.Binding.Id);

var hasCycle = path.TryGetValue(depNode.Binding.Id, out var cycleVariable);
var isAlreadyCreated = false;
if (hasCycle)
{
Expand All @@ -119,7 +118,7 @@ public Block Build(
depNode with { Accumulators = accumulators },
depInjection,
ref transientId,
hasCycle);
cycleVariable);

var isBlock = depNode.Lifetime is not Lifetime.Transient and not Lifetime.PerBlock
|| nodeInfo.IsDelegate(variable.Node)
Expand Down Expand Up @@ -190,16 +189,27 @@ private Variable GetVariable(
DependencyNode node,
in Injection injection,
ref int transientId,
bool hasCycle)
Variable? cycleVariable = default)
{
if (cycleVariable is not null)
{
return cycleVariable with
{
Parent = parentBlock,
Injection = injection,
Args = new List<IStatement>(),
HasCycle = true
};
}

if (node.Arg is null)
{
// ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
switch (node.Lifetime)
{
case Lifetime.Transient:
{
var transientVariable = new Variable(setup, parentBlock, transientId++, node, injection, new List<IStatement>(), new VariableInfo(), nodeInfo.IsLazy(node), hasCycle);
var transientVariable = new Variable(setup, parentBlock, transientId++, node, injection, new List<IStatement>(), new VariableInfo(), nodeInfo.IsLazy(node), false);
if (node.Construct?.Source.Kind == MdConstructKind.Accumulator)
{
transientVariable.VariableCode = GetAccumulatorName(transientVariable);
Expand All @@ -217,12 +227,11 @@ private Variable GetVariable(
{
Parent = parentBlock,
Injection = injection,
Args = new List<IStatement>(),
HasCycle = hasCycle
Args = new List<IStatement>()
};
}

blockVariable = new Variable(setup, parentBlock, transientId++, node, injection, new List<IStatement>(), new VariableInfo(), nodeInfo.IsLazy(node), hasCycle);
blockVariable = new Variable(setup, parentBlock, transientId++, node, injection, new List<IStatement>(), new VariableInfo(), nodeInfo.IsLazy(node), false);
blockMap.Add(perBlockKey, blockVariable);
return blockVariable;
}
Expand All @@ -236,12 +245,11 @@ private Variable GetVariable(
{
Parent = parentBlock,
Injection = injection,
Args = new List<IStatement>(),
HasCycle = hasCycle
Args = new List<IStatement>()
};
}

variable = new Variable(setup, parentBlock, node.Binding.Id, node, injection, new List<IStatement>(), new VariableInfo(), nodeInfo.IsLazy(node), hasCycle);
variable = new Variable(setup, parentBlock, node.Binding.Id, node, injection, new List<IStatement>(), new VariableInfo(), nodeInfo.IsLazy(node), false);
map.Add(node.Binding, variable);
return variable;
}
Expand Down
6 changes: 3 additions & 3 deletions src/Pure.DI.Core/Features/Default.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private static void Setup()
return new Owned<TT>(value, owned);
})
.Bind<global::System.Func<TT>>()
.As(Lifetime.PerResolve)
.As(Lifetime.PerBlock)
.To(ctx => new global::System.Func<TT>(() =>
{
ctx.Inject<TT>(ctx.Tag, out var value);
Expand Down Expand Up @@ -180,8 +180,8 @@ private static void Setup()
#if NETCOREAPP2_0 || NET || NETSTANDARD2_0_OR_GREATER
.Bind<global::System.Text.Encoding>().To(_ => global::System.Text.Encoding.Default)
#endif
.Bind<global::System.Text.Decoder>().To((global::System.Text.Encoding encoding) => encoding.GetDecoder())
.Bind<global::System.Text.Encoder>().To((global::System.Text.Encoding encoding) => encoding.GetEncoder())
.Bind<global::System.Text.Decoder>().As(Lifetime.PerBlock).To((global::System.Text.Encoding encoding) => encoding.GetDecoder())
.Bind<global::System.Text.Encoder>().As(Lifetime.PerBlock).To((global::System.Text.Encoding encoding) => encoding.GetEncoder())
;
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/Pure.DI.IntegrationTests/PartialMethodsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public static void Main()

// Then
result.Success.ShouldBeTrue(result);
result.StdOut.ShouldBe(["System.Func`1[Sample.IDependency] '' PerResolve created", "Sample.Dependency '' Singleton created", "Sample.Service '' Transient created"], result);
result.StdOut.ShouldBe(["System.Func`1[Sample.IDependency] '' PerBlock created", "Sample.Dependency '' Singleton created", "Sample.Service '' Transient created"], result);
}

[Fact]
Expand Down Expand Up @@ -345,7 +345,7 @@ public static void Main()

// Then
result.Success.ShouldBeTrue(result);
result.StdOut.ShouldBe(["Sample.IDependency '' Singleton injected", "System.Func`1[Sample.IDependency] '' PerResolve injected", "Sample.IDependency '' Singleton injected", "Sample.IService '' Transient injected"], result);
result.StdOut.ShouldBe(["Sample.IDependency '' Singleton injected", "System.Func`1[Sample.IDependency] '' PerBlock injected", "Sample.IDependency '' Singleton injected", "Sample.IService '' Transient injected"], result);
}

[Fact]
Expand Down

0 comments on commit 9df0cec

Please sign in to comment.