diff --git a/readme/tag-unique.md b/readme/tag-unique.md index da5f87a47..d91908dec 100644 --- a/readme/tag-unique.md +++ b/readme/tag-unique.md @@ -46,11 +46,11 @@ classDiagram + object Resolve(Type type, object? tag) } class IEnumerableᐸIDependencyᐸStringᐳᐳ - AbcDependencyᐸStringᐳ --|> IDependencyᐸStringᐳ : cf28a5f5-c0c6-4d80-9869-561448e661e1 + AbcDependencyᐸStringᐳ --|> IDependencyᐸStringᐳ : Unique tag 1 class AbcDependencyᐸStringᐳ { +AbcDependency() } - XyzDependencyᐸStringᐳ --|> IDependencyᐸStringᐳ : 0c31c79e-0327-4b14-9fc1-166a5a5aa440 + XyzDependencyᐸStringᐳ --|> IDependencyᐸStringᐳ : Unique tag 2 class XyzDependencyᐸStringᐳ { +XyzDependency() } @@ -64,8 +64,8 @@ classDiagram class IServiceᐸStringᐳ { <> } - IEnumerableᐸIDependencyᐸStringᐳᐳ *-- AbcDependencyᐸStringᐳ : cf28a5f5-c0c6-4d80-9869-561448e661e1 IDependencyᐸStringᐳ - IEnumerableᐸIDependencyᐸStringᐳᐳ *-- XyzDependencyᐸStringᐳ : 0c31c79e-0327-4b14-9fc1-166a5a5aa440 IDependencyᐸStringᐳ + IEnumerableᐸIDependencyᐸStringᐳᐳ *-- AbcDependencyᐸStringᐳ : Unique tag 1 IDependencyᐸStringᐳ + IEnumerableᐸIDependencyᐸStringᐳᐳ *-- XyzDependencyᐸStringᐳ : Unique tag 2 IDependencyᐸStringᐳ Composition ..> ServiceᐸStringᐳ : IServiceᐸStringᐳ Root ServiceᐸStringᐳ o-- "PerBlock" IEnumerableᐸIDependencyᐸStringᐳᐳ : IEnumerableᐸIDependencyᐸStringᐳᐳ ``` @@ -157,11 +157,11 @@ partial class Composition " + object Resolve(Type type, object? tag)\n" + " }\n" + " class IEnumerableᐸIDependencyᐸStringᐳᐳ\n" + - " AbcDependencyᐸStringᐳ --|> IDependencyᐸStringᐳ : cf28a5f5-c0c6-4d80-9869-561448e661e1 \n" + + " AbcDependencyᐸStringᐳ --|> IDependencyᐸStringᐳ : Unique tag 1 \n" + " class AbcDependencyᐸStringᐳ {\n" + " +AbcDependency()\n" + " }\n" + - " XyzDependencyᐸStringᐳ --|> IDependencyᐸStringᐳ : 0c31c79e-0327-4b14-9fc1-166a5a5aa440 \n" + + " XyzDependencyᐸStringᐳ --|> IDependencyᐸStringᐳ : Unique tag 2 \n" + " class XyzDependencyᐸStringᐳ {\n" + " +XyzDependency()\n" + " }\n" + @@ -175,8 +175,8 @@ partial class Composition " class IServiceᐸStringᐳ {\n" + " <>\n" + " }\n" + - " IEnumerableᐸIDependencyᐸStringᐳᐳ *-- AbcDependencyᐸStringᐳ : cf28a5f5-c0c6-4d80-9869-561448e661e1 IDependencyᐸStringᐳ\n" + - " IEnumerableᐸIDependencyᐸStringᐳᐳ *-- XyzDependencyᐸStringᐳ : 0c31c79e-0327-4b14-9fc1-166a5a5aa440 IDependencyᐸStringᐳ\n" + + " IEnumerableᐸIDependencyᐸStringᐳᐳ *-- AbcDependencyᐸStringᐳ : Unique tag 1 IDependencyᐸStringᐳ\n" + + " IEnumerableᐸIDependencyᐸStringᐳᐳ *-- XyzDependencyᐸStringᐳ : Unique tag 2 IDependencyᐸStringᐳ\n" + " Composition ..> ServiceᐸStringᐳ : IServiceᐸStringᐳ Root\n" + " ServiceᐸStringᐳ o-- \"PerBlock\" IEnumerableᐸIDependencyᐸStringᐳᐳ : IEnumerableᐸIDependencyᐸStringᐳᐳ"; } diff --git a/readme/tracking-disposable-instances-per-a-composition-root.md b/readme/tracking-disposable-instances-per-a-composition-root.md index 3012b9e60..6133bfa54 100644 --- a/readme/tracking-disposable-instances-per-a-composition-root.md +++ b/readme/tracking-disposable-instances-per-a-composition-root.md @@ -25,20 +25,6 @@ class Service(IDependency dependency) : IService public IDependency Dependency { get; } = dependency; } -readonly struct Owned( - T value, - List disposables) - : IDisposable -{ - public T Value { get; } = value; - - public void Dispose() - { - disposables.Reverse(); - disposables.ForEach(i => i.Dispose()); - } -} - partial class Composition { private List _disposables = []; @@ -49,39 +35,42 @@ partial class Composition // when an instance is created .Hint(Hint.OnNewInstance, "On") - // Specifies to call the partial method OnNewInstance + // Specifies to call the partial method // only for instances with lifetime // Transient, PerResolve and PerBlock - .Hint( - Hint.OnNewInstanceLifetimeRegularExpression, + .Hint(Hint.OnNewInstanceLifetimeRegularExpression, "Transient|PerResolve|PerBlock") - // Specifies to call the partial method OnNewInstance - // for instances other than Composition.Owned - .Hint( - Hint.OnNewInstanceImplementationTypeNameRegularExpression, - "^((?!Owned<).)*$") - - .Bind().To(ctx => - { - ctx.Inject(out TT value); - var disposables = _disposables; - _disposables = []; - return new Owned(value, disposables); - }) - .Bind().To() .Bind().To() .Root>("Root"); - partial void OnNewInstance( - ref T value, - object? tag, - Lifetime lifetime) + partial void OnNewInstance(ref T value, object? tag, Lifetime lifetime) { - if (value is not IDisposable disposable) return; + if (value is IOwned || value is not IDisposable disposable) return; _disposables.Add(disposable); } + + public interface IOwned; + + public readonly struct Owned: IDisposable, IOwned + { + public readonly T Value; + private readonly List _disposable; + + public Owned(T value, Composition composition) + { + Value = value; + _disposable = composition._disposables; + composition._disposables = []; + } + + public void Dispose() + { + _disposable.Reverse(); + _disposable.ForEach(i => i.Dispose()); + } + } } var composition = new Composition(); @@ -118,6 +107,10 @@ classDiagram + object Resolve(Type type) + object Resolve(Type type, object? tag) } + class Composition + class OwnedᐸIServiceᐳ { + +Owned(IService value, Composition composition) + } Dependency --|> IDependency : class Dependency { +Dependency() @@ -132,9 +125,10 @@ classDiagram class IService { <> } + OwnedᐸIServiceᐳ *-- Service : IService + OwnedᐸIServiceᐳ *-- Composition : Composition Service *-- Dependency : IDependency Composition ..> OwnedᐸIServiceᐳ : OwnedᐸIServiceᐳ Root - OwnedᐸIServiceᐳ *-- Service : IService ``` @@ -157,21 +151,17 @@ partial class Composition _rootM03D18di = baseComposition._rootM03D18di; } - public Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Owned Root + public Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Composition.Owned Root { get { - Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Dependency transientM03D18di2_Dependency = new Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Dependency(); - OnNewInstance(ref transientM03D18di2_Dependency, null, Pure.DI.Lifetime.Transient); - Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Service transientM03D18di1_Service = new Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Service(transientM03D18di2_Dependency); + Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Dependency transientM03D18di3_Dependency = new Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Dependency(); + OnNewInstance(ref transientM03D18di3_Dependency, null, Pure.DI.Lifetime.Transient); + Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Composition transientM03D18di2_Composition = this; + Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Service transientM03D18di1_Service = new Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Service(transientM03D18di3_Dependency); OnNewInstance(ref transientM03D18di1_Service, null, Pure.DI.Lifetime.Transient); - Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Owned transientM03D18di0_Owned; - { - var value_M03D18di1 = transientM03D18di1_Service; - var disposables_M03D18di2 = _disposables; - _disposables = []; - transientM03D18di0_Owned = new Owned(value_M03D18di1, disposables_M03D18di2); - } + Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Composition.Owned transientM03D18di0_Owned = new Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Composition.Owned(transientM03D18di1_Service, transientM03D18di2_Composition); + OnNewInstance>(ref transientM03D18di0_Owned, null, Pure.DI.Lifetime.Transient); return transientM03D18di0_Owned; } } @@ -229,6 +219,10 @@ partial class Composition " + object Resolve(Type type)\n" + " + object Resolve(Type type, object? tag)\n" + " }\n" + + " class Composition\n" + + " class OwnedᐸIServiceᐳ {\n" + + " +Owned(IService value, Composition composition)\n" + + " }\n" + " Dependency --|> IDependency : \n" + " class Dependency {\n" + " +Dependency()\n" + @@ -243,9 +237,10 @@ partial class Composition " class IService {\n" + " <>\n" + " }\n" + + " OwnedᐸIServiceᐳ *-- Service : IService\n" + + " OwnedᐸIServiceᐳ *-- Composition : Composition\n" + " Service *-- Dependency : IDependency\n" + - " Composition ..> OwnedᐸIServiceᐳ : OwnedᐸIServiceᐳ Root\n" + - " OwnedᐸIServiceᐳ *-- Service : IService"; + " Composition ..> OwnedᐸIServiceᐳ : OwnedᐸIServiceᐳ Root"; } private readonly static int _bucketSizeM03D18di; @@ -254,13 +249,13 @@ partial class Composition static Composition() { var valResolverM03D18di_0000 = new ResolverM03D18di_0000(); - ResolverM03D18di>.Value = valResolverM03D18di_0000; + ResolverM03D18di>.Value = valResolverM03D18di_0000; _bucketsM03D18di = global::Pure.DI.Buckets>.Create( 1, out _bucketSizeM03D18di, new global::Pure.DI.Pair>[1] { - new global::Pure.DI.Pair>(typeof(Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Owned), valResolverM03D18di_0000) + new global::Pure.DI.Pair>(typeof(Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Composition.Owned), valResolverM03D18di_0000) }); } @@ -279,21 +274,21 @@ partial class Composition } } - private sealed class ResolverM03D18di_0000: global::Pure.DI.IResolver>, global::Pure.DI.IResolver + private sealed class ResolverM03D18di_0000: global::Pure.DI.IResolver>, global::Pure.DI.IResolver { - public Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Owned Resolve(Composition composition) + public Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Composition.Owned Resolve(Composition composition) { return composition.Root; } - public Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Owned ResolveByTag(Composition composition, object tag) + public Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Composition.Owned ResolveByTag(Composition composition, object tag) { switch (tag) { case null: return composition.Root; } - throw new global::System.InvalidOperationException($"Cannot resolve composition root \"{tag}\" of type Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Owned."); + throw new global::System.InvalidOperationException($"Cannot resolve composition root \"{tag}\" of type Pure.DI.UsageTests.Hints.TrackingDisposableInstancesPerRootScenario.Composition.Owned."); } object global::Pure.DI.IResolver.Resolve(Composition composition) { diff --git a/src/Pure.DI.Core/Core/BindingBuilder.cs b/src/Pure.DI.Core/Core/BindingBuilder.cs index bb9d6a720..0ac02604b 100644 --- a/src/Pure.DI.Core/Core/BindingBuilder.cs +++ b/src/Pure.DI.Core/Core/BindingBuilder.cs @@ -2,7 +2,9 @@ namespace Pure.DI.Core; internal class BindingBuilder( + [Tag("UniqueTags")] IIdGenerator idGenerator, IBaseSymbolsProvider baseSymbolsProvider) + : IBindingBuilder { private MdDefaultLifetime? _defaultLifetime; private SemanticModel? _semanticModel; @@ -138,7 +140,7 @@ public MdBinding Build(MdSetup setup) } } - private static MdTag BuildTag(MdTag tag, ITypeSymbol? type) + private MdTag BuildTag(MdTag tag, ITypeSymbol? type) { if (type is null || tag.Value is null) { @@ -154,7 +156,7 @@ private static MdTag BuildTag(MdTag tag, ITypeSymbol? type) return tag with { Value = type }; case Tag.Unique: - return tag with { Value = Guid.NewGuid() }; + return tag with { Value = new UniqueTag(idGenerator.Generate()) }; } } diff --git a/src/Pure.DI.Core/Core/Code/BuildTools.cs b/src/Pure.DI.Core/Core/Code/BuildTools.cs index a802642d7..d9e8a1a13 100644 --- a/src/Pure.DI.Core/Core/Code/BuildTools.cs +++ b/src/Pure.DI.Core/Core/Code/BuildTools.cs @@ -11,7 +11,7 @@ public void AddPureHeader(LinesBuilder code) code.AppendLine("#endif"); } - public string GetDeclaration(Variable variable, bool typeIsRequired = false) => + public string GetDeclaration(Variable variable) => variable.IsDeclared ? "" : $"{typeResolver.Resolve(variable.InstanceType)} "; public string OnInjected(BuildContext ctx, Variable variable) diff --git a/src/Pure.DI.Core/Core/Code/ConstructCodeBuilder.cs b/src/Pure.DI.Core/Core/Code/ConstructCodeBuilder.cs index efd0ca26c..be75d7fc0 100644 --- a/src/Pure.DI.Core/Core/Code/ConstructCodeBuilder.cs +++ b/src/Pure.DI.Core/Core/Code/ConstructCodeBuilder.cs @@ -102,7 +102,7 @@ private static void BuildSpan(BuildContext ctx, in DpConstruct span) && span.Binding.SemanticModel.Compilation.GetLanguageVersion() >= LanguageVersion.CSharp7_3; var createInstance = isStackalloc ? $"stackalloc {createArray}" : $"new {Names.SystemNamespace}Span<{span.Source.ElementType}>(new {createArray})"; - ctx.Code.AppendLine($"{ctx.BuildTools.GetDeclaration(variable, isStackalloc)}{variable.VariableName} = {createInstance};"); + ctx.Code.AppendLine($"{ctx.BuildTools.GetDeclaration(variable)}{variable.VariableName} = {createInstance};"); ctx.Code.AppendLines(ctx.BuildTools.OnCreated(ctx, variable)); } diff --git a/src/Pure.DI.Core/Core/Code/FactoryCodeBuilder.cs b/src/Pure.DI.Core/Core/Code/FactoryCodeBuilder.cs index c1a0b5ae7..3d58de0ab 100644 --- a/src/Pure.DI.Core/Core/Code/FactoryCodeBuilder.cs +++ b/src/Pure.DI.Core/Core/Code/FactoryCodeBuilder.cs @@ -32,13 +32,13 @@ public void Build(BuildContext ctx, in DpFactory factory) SyntaxNode syntaxNode = lambda.Block is not null ? lambda.Block : SyntaxFactory.ExpressionStatement((ExpressionSyntax)lambda.Body); if (syntaxNode is not BlockSyntax) { - code.Append($"{ctx.BuildTools.GetDeclaration(variable, true)}{variable.VariableName} = "); + code.Append($"{ctx.BuildTools.GetDeclaration(variable)}{variable.VariableName} = "); } else { if (!variable.IsDeclared) { - code.AppendLine($"{ctx.BuildTools.GetDeclaration(variable, true)}{variable.VariableName};"); + code.AppendLine($"{ctx.BuildTools.GetDeclaration(variable)}{variable.VariableName};"); } } diff --git a/src/Pure.DI.Core/Core/Code/IBuildTools.cs b/src/Pure.DI.Core/Core/Code/IBuildTools.cs index 73c7ce4a2..238ad8c7f 100644 --- a/src/Pure.DI.Core/Core/Code/IBuildTools.cs +++ b/src/Pure.DI.Core/Core/Code/IBuildTools.cs @@ -4,7 +4,7 @@ internal interface IBuildTools { void AddPureHeader(LinesBuilder code); - string GetDeclaration(Variable variable, bool typeIsRequired = false); + string GetDeclaration(Variable variable); string OnInjected(BuildContext ctx, Variable variable); diff --git a/src/Pure.DI.Core/Core/IBindingBuilder.cs b/src/Pure.DI.Core/Core/IBindingBuilder.cs new file mode 100644 index 000000000..d7a75c733 --- /dev/null +++ b/src/Pure.DI.Core/Core/IBindingBuilder.cs @@ -0,0 +1,20 @@ +namespace Pure.DI.Core; + +internal interface IBindingBuilder +{ + MdDefaultLifetime DefaultLifetime { set; } + + MdLifetime Lifetime { set; } + + MdImplementation Implementation { set; } + + MdFactory Factory { set; } + + MdArg Arg { set; } + + void AddContract(in MdContract contract); + + void AddTag(in MdTag tag); + + MdBinding Build(MdSetup setup); +} \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/SetupsBuilder.cs b/src/Pure.DI.Core/Core/SetupsBuilder.cs index 9cbe17021..870e88e60 100644 --- a/src/Pure.DI.Core/Core/SetupsBuilder.cs +++ b/src/Pure.DI.Core/Core/SetupsBuilder.cs @@ -4,7 +4,7 @@ namespace Pure.DI.Core; internal sealed class SetupsBuilder( Func metadataSyntaxWalkerFactory, ICache, bool> setupCache, - IBaseSymbolsProvider baseSymbolsProvider) + Func bindingBuilderFactory) : IBuilder>, IMetadataVisitor { private readonly List _setups = []; @@ -15,7 +15,7 @@ internal sealed class SetupsBuilder( private readonly List _tagAttributes = []; private readonly List _ordinalAttributes = []; private readonly List _usingDirectives = []; - private BindingBuilder _bindingBuilder = new(baseSymbolsProvider); + private IBindingBuilder _bindingBuilder = bindingBuilderFactory(); private MdSetup? _setup; public IEnumerable Build(SyntaxUpdate update) @@ -127,6 +127,6 @@ setup with _ordinalAttributes.Clear(); _usingDirectives.Clear(); _setup = default; - _bindingBuilder = new BindingBuilder(baseSymbolsProvider); + _bindingBuilder = bindingBuilderFactory(); } } \ No newline at end of file diff --git a/src/Pure.DI.Core/Core/UniqueTag.cs b/src/Pure.DI.Core/Core/UniqueTag.cs new file mode 100644 index 000000000..0f2d2506f --- /dev/null +++ b/src/Pure.DI.Core/Core/UniqueTag.cs @@ -0,0 +1,8 @@ +// ReSharper disable NotAccessedPositionalProperty.Global +namespace Pure.DI.Core; + +internal record UniqueTag(int Id) +{ + public override string ToString() => + $"Unique tag {Id}"; +} \ No newline at end of file diff --git a/src/Pure.DI.Core/Generator.Composition.cs b/src/Pure.DI.Core/Generator.Composition.cs index 88c2dbbea..fbe130807 100644 --- a/src/Pure.DI.Core/Generator.Composition.cs +++ b/src/Pure.DI.Core/Generator.Composition.cs @@ -32,6 +32,7 @@ private static void Setup() => DI.Setup(nameof(Generator)) .Bind().To() .Bind().To() .Bind>().To(_ => StringComparer.InvariantCultureIgnoreCase) + .Bind().To() // Singleton .DefaultLifetime(Singleton) @@ -118,5 +119,6 @@ private static void Setup() => DI.Setup(nameof(Generator)) .Bind().To() .Bind().To() .Bind().To() + .Bind("UniqueTags").To() .Bind().To(); } \ No newline at end of file diff --git a/tests/Pure.DI.UsageTests/Hints/TrackingDisposableInstancesPerRootScenario.cs b/tests/Pure.DI.UsageTests/Hints/TrackingDisposableInstancesPerRootScenario.cs index 0299011a0..015aa7946 100644 --- a/tests/Pure.DI.UsageTests/Hints/TrackingDisposableInstancesPerRootScenario.cs +++ b/tests/Pure.DI.UsageTests/Hints/TrackingDisposableInstancesPerRootScenario.cs @@ -35,20 +35,6 @@ class Service(IDependency dependency) : IService public IDependency Dependency { get; } = dependency; } -readonly struct Owned( - T value, - List disposables) - : IDisposable -{ - public T Value { get; } = value; - - public void Dispose() - { - disposables.Reverse(); - disposables.ForEach(i => i.Dispose()); - } -} - partial class Composition { private List _disposables = []; @@ -59,39 +45,42 @@ private void Setup() => // when an instance is created .Hint(Hint.OnNewInstance, "On") - // Specifies to call the partial method OnNewInstance + // Specifies to call the partial method // only for instances with lifetime // Transient, PerResolve and PerBlock - .Hint( - Hint.OnNewInstanceLifetimeRegularExpression, + .Hint(Hint.OnNewInstanceLifetimeRegularExpression, "Transient|PerResolve|PerBlock") - // Specifies to call the partial method OnNewInstance - // for instances other than Composition.Owned - .Hint( - Hint.OnNewInstanceImplementationTypeNameRegularExpression, - "^((?!Owned<).)*$") - - .Bind().To(ctx => - { - ctx.Inject(ctx.Tag, out TT value); - var disposables = _disposables; - _disposables = []; - return new Owned(value, disposables); - }) - .Bind().To() .Bind().To() .Root>("Root"); - partial void OnNewInstance( - ref T value, - object? tag, - Lifetime lifetime) + partial void OnNewInstance(ref T value, object? tag, Lifetime lifetime) { - if (value is not IDisposable disposable) return; + if (value is IOwned || value is not IDisposable disposable) return; _disposables.Add(disposable); } + + public interface IOwned; + + public readonly struct Owned: IDisposable, IOwned + { + public readonly T Value; + private readonly List _disposable; + + public Owned(T value, Composition composition) + { + Value = value; + _disposable = composition._disposables; + composition._disposables = []; + } + + public void Dispose() + { + _disposable.Reverse(); + _disposable.ForEach(i => i.Dispose()); + } + } } // }