From 287360eb50756fb5421dfaf4354fb4f07aacb986 Mon Sep 17 00:00:00 2001 From: Peter Csajtai Date: Sat, 18 Mar 2017 14:03:14 +0100 Subject: [PATCH] Added open generic decorator support, few fixes --- appveyor.yml | 4 +- src/stashbox.tests/ContainerTests.cs | 31 +-- src/stashbox.tests/DecoratorTests.cs | 188 +++++++++++++++++- src/stashbox.tests/DisposeTests.cs | 6 +- src/stashbox.tests/EnumerableTests.cs | 15 +- .../BuildUp/GenericTypeObjectBuilder.cs | 27 +-- src/stashbox/BuildUp/ObjectBuilderBase.cs | 19 +- .../Resolution/ParentContainerResolver.cs | 3 +- .../Configuration/ContainerConfiguration.cs | 8 +- .../Configuration/ContainerConfigurator.cs | 7 - src/stashbox/Entity/ResolutionInfo.cs | 7 +- .../Infrastructure/IContainerConfigurator.cs | 6 - .../Registration/RegistrationContextBase.cs | 4 +- .../Registration/ScopedRegistrationContext.cs | 11 +- src/stashbox/Utils/AvlTree.cs | 34 +++- 15 files changed, 275 insertions(+), 95 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index f774d07d..d6b0d5ef 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ artifact: /.*\.nupkg/ environment: - build_version: 2.3.0 + build_version: 2.3.1 COVERALLS_REPO_TOKEN: secure: Q9gcbZnzJ5a0YYF6mkr4QoQylIzeQmVytMnIe4WL7aPtb30SdNes7brLkvnXOirt @@ -79,7 +79,7 @@ secure: 2bITagXOj2s3bTJaGXh8/iyWtST8OQOFaMM+0GAKgZts9OjCVCiV7C+E/0SYsM6M environment: - build_version: 2.3.0 + build_version: 2.3.1 COVERALLS_REPO_TOKEN: secure: Q9gcbZnzJ5a0YYF6mkr4QoQylIzeQmVytMnIe4WL7aPtb30SdNes7brLkvnXOirt diff --git a/src/stashbox.tests/ContainerTests.cs b/src/stashbox.tests/ContainerTests.cs index b142b104..6d61eb73 100644 --- a/src/stashbox.tests/ContainerTests.cs +++ b/src/stashbox.tests/ContainerTests.cs @@ -17,7 +17,7 @@ public class ContainerTests [TestMethod] public void ContainerTests_ChildContainer() { - var container = new StashboxContainer(config => config.WithParentContainerResolution()); + var container = new StashboxContainer(); container.RegisterType(); container.RegisterType(); @@ -33,47 +33,18 @@ public void ContainerTests_ChildContainer() [TestMethod] public void ContainerTests_ChildContainer_ResolveFromParent() - { - var container = new StashboxContainer(config => config.WithParentContainerResolution()); - container.RegisterType(); - - var child = container.BeginScope(); - - var test1 = child.Resolve(); - - Assert.IsNotNull(test1); - Assert.IsInstanceOfType(test1, typeof(Test1)); - } - - [TestMethod] - public void ContainerTests_ChildContainer_ResolveFromParent_WithConfigure() { var container = new StashboxContainer(); container.RegisterType(); var child = container.BeginScope(); - container.Configure(config => config.WithParentContainerResolution()); var test1 = child.Resolve(); Assert.IsNotNull(test1); Assert.IsInstanceOfType(test1, typeof(Test1)); } - [TestMethod] - [ExpectedException(typeof(ResolutionFailedException))] - public void ContainerTests_ChildContainer_WithoutResolveFromParent() - { - using (var container = new StashboxContainer()) - { - container.RegisterType(); - - var child = container.BeginScope(); - - var test1 = child.Resolve(); - } - } - [TestMethod] [ExpectedException(typeof(ResolutionFailedException))] public void ContainerTests_Validate_MissingDependency() diff --git a/src/stashbox.tests/DecoratorTests.cs b/src/stashbox.tests/DecoratorTests.cs index 2f945e7f..f22cdf6e 100644 --- a/src/stashbox.tests/DecoratorTests.cs +++ b/src/stashbox.tests/DecoratorTests.cs @@ -1,4 +1,7 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Stashbox.Attributes; using Stashbox.Configuration; using Stashbox.Entity; @@ -59,6 +62,120 @@ public void DecoratorTests_Simple3() } } + [TestMethod] + public void DecoratorTests_Simple_Lazy() + { + using (var container = new StashboxContainer()) + { + container.RegisterType(); + container.RegisterDecorator(); + var test = container.Resolve>(); + + Assert.IsNotNull(test.Value); + Assert.IsInstanceOfType(test.Value, typeof(TestDecorator1)); + + Assert.IsNotNull(test.Value.Test); + Assert.IsInstanceOfType(test.Value.Test, typeof(Test1)); + } + } + + [TestMethod] + public void DecoratorTests_Simple_Func() + { + using (var container = new StashboxContainer()) + { + container.RegisterType(); + container.RegisterDecorator(); + var test = container.Resolve>(); + + Assert.IsNotNull(test()); + Assert.IsInstanceOfType(test(), typeof(TestDecorator1)); + + Assert.IsNotNull(test().Test); + Assert.IsInstanceOfType(test().Test, typeof(Test1)); + } + } + + [TestMethod] + public void DecoratorTests_Simple_Enumerable() + { + using (var container = new StashboxContainer(config => config.WithEnumerableOrderRule(Rules.EnumerableOrder.PreserveOrder))) + { + container.RegisterType(); + container.RegisterType(); + container.RegisterDecorator(); + var test = container.Resolve>(); + + Assert.IsNotNull(test); + Assert.IsInstanceOfType(test, typeof(IEnumerable)); + + var arr = test.ToArray(); + + Assert.IsNotNull(arr[0]); + Assert.IsInstanceOfType(arr[0], typeof(TestDecorator1)); + + Assert.IsNotNull(arr[1]); + Assert.IsInstanceOfType(arr[1], typeof(TestDecorator1)); + + Assert.IsNotNull(arr[0].Test); + Assert.IsInstanceOfType(arr[0].Test, typeof(Test1)); + + Assert.IsNotNull(arr[1].Test); + Assert.IsInstanceOfType(arr[1].Test, typeof(Test11)); + } + } + + [TestMethod] + public void DecoratorTests_Decorator_Holds_Lazy() + { + using (var container = new StashboxContainer()) + { + container.RegisterType(); + container.RegisterDecorator(); + var test = container.Resolve(); + + Assert.IsNotNull(test); + Assert.IsInstanceOfType(test, typeof(TestDecorator6)); + + Assert.IsNotNull(test.Test); + Assert.IsInstanceOfType(test.Test, typeof(Test1)); + } + } + + [TestMethod] + public void DecoratorTests_Decorator_Holds_Func() + { + using (var container = new StashboxContainer()) + { + container.RegisterType(); + container.RegisterDecorator(); + var test = container.Resolve(); + + Assert.IsNotNull(test); + Assert.IsInstanceOfType(test, typeof(TestDecorator7)); + + Assert.IsNotNull(test.Test); + Assert.IsInstanceOfType(test.Test, typeof(Test1)); + } + } + + [TestMethod] + public void DecoratorTests_Decorator_Holds_Enumerable() + { + using (var container = new StashboxContainer()) + { + container.RegisterType(); + container.RegisterDecorator(); + var test = container.Resolve(); + + Assert.IsNotNull(test); + Assert.IsInstanceOfType(test, typeof(TestDecorator8)); + + Assert.IsNotNull(test.Test); + Assert.IsInstanceOfType(test.Test, typeof(Test1)); + } + } + [TestMethod] public void DecoratorTests_Dependency() { @@ -199,13 +316,52 @@ public void DecoratorTests_Multiple_Scoped() } } + [TestMethod] + public void DecoratorTests_OpenGeneric() + { + using (var container = new StashboxContainer()) + { + container.RegisterType(typeof(ITest1<>), typeof(Test1<>)); + container.RegisterDecorator(typeof(ITest1<>), typeof(TestDecorator1<>)); + var test = container.Resolve>(); + + Assert.IsNotNull(test); + Assert.IsInstanceOfType(test, typeof(TestDecorator1)); + + Assert.IsNotNull(test.Test); + Assert.IsInstanceOfType(test.Test, typeof(Test1)); + } + } + public interface ITest1 { ITest1 Test { get; } } + public interface ITest1 { ITest1 Test { get; } } + public class Test1 : ITest1 { public ITest1 Test { get; } } + public class Test11 : ITest1 + { + public ITest1 Test { get; } + } + + public class Test1 : ITest1 + { + public ITest1 Test { get; } + } + + public class TestDecorator1 : ITest1 + { + public ITest1 Test { get; } + + public TestDecorator1(ITest1 test1) + { + this.Test = test1; + } + } + public class TestDecorator1 : ITest1 { public ITest1 Test { get; } @@ -251,5 +407,35 @@ public TestDecorator5(ITest1 test1) this.Test = test1; } } + + public class TestDecorator6 : ITest1 + { + public ITest1 Test { get; } + + public TestDecorator6(Lazy test1) + { + this.Test = test1.Value; + } + } + + public class TestDecorator7 : ITest1 + { + public ITest1 Test { get; } + + public TestDecorator7(Func test1) + { + this.Test = test1(); + } + } + + public class TestDecorator8 : ITest1 + { + public ITest1 Test { get; } + + public TestDecorator8(IEnumerable test1) + { + this.Test = test1.First(); + } + } } } diff --git a/src/stashbox.tests/DisposeTests.cs b/src/stashbox.tests/DisposeTests.cs index bd9e5c16..1acfa634 100644 --- a/src/stashbox.tests/DisposeTests.cs +++ b/src/stashbox.tests/DisposeTests.cs @@ -133,7 +133,7 @@ public void DisposeTests_TrackTransientDisposal_Scoped_Transient() ITest1 test; ITest2 test2; Test3 test3; - using (IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking().WithParentContainerResolution())) + using (IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking())) { ITest1 test4; ITest2 test5; @@ -167,7 +167,7 @@ public void DisposeTests_TrackTransientDisposal_Scoped_Transient() [TestMethod] public void DisposeTests_TrackTransientDisposal_Scoped_Transient_ChildContainer() { - IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking().WithParentContainerResolution()); + IStashboxContainer container = new StashboxContainer(config => config.WithDisposableTransientTracking()); ITest1 test4; ITest2 test5; Test3 test6; @@ -191,7 +191,7 @@ public void DisposeTests_TrackTransientDisposal_Scoped_Transient_ChildContainer( [TestMethod] public void DisposeTests_TrackTransientDisposal_Scoped_Transient_Singleton() { - var container = new StashboxContainer(config => config.WithDisposableTransientTracking().WithParentContainerResolution()); + var container = new StashboxContainer(config => config.WithDisposableTransientTracking()); container.RegisterType(); diff --git a/src/stashbox.tests/EnumerableTests.cs b/src/stashbox.tests/EnumerableTests.cs index e34e9f43..ba342848 100644 --- a/src/stashbox.tests/EnumerableTests.cs +++ b/src/stashbox.tests/EnumerableTests.cs @@ -100,7 +100,7 @@ public void EnumerableTests_Resolve() [TestMethod] public void EnumerableTests_Resolve_Parent() { - IStashboxContainer container = new StashboxContainer(config => config.WithParentContainerResolution()); + IStashboxContainer container = new StashboxContainer(); container.RegisterType(); container.RegisterType(); container.RegisterType(); @@ -115,7 +115,7 @@ public void EnumerableTests_Resolve_Parent() [TestMethod] public void EnumerableTests_Resolve_Parent_Lazy() { - IStashboxContainer container = new StashboxContainer(config => config.WithParentContainerResolution()); + IStashboxContainer container = new StashboxContainer(); container.RegisterType(); container.RegisterType(); container.RegisterType(); @@ -130,7 +130,7 @@ public void EnumerableTests_Resolve_Parent_Lazy() [TestMethod] public void EnumerableTests_Resolve_Parent_Func() { - IStashboxContainer container = new StashboxContainer(config => config.WithParentContainerResolution()); + IStashboxContainer container = new StashboxContainer(); container.RegisterType(); container.RegisterType(); container.RegisterType(); @@ -267,8 +267,7 @@ public void EnumerableTests_ResolveAll_PreserveOrder() public void EnumerableTests_Resolve_PreserveOrder_Parent() { IStashboxContainer container = new StashboxContainer(config => - config.WithEnumerableOrderRule(Rules.EnumerableOrder.PreserveOrder) - .WithParentContainerResolution()); + config.WithEnumerableOrderRule(Rules.EnumerableOrder.PreserveOrder)); container.RegisterType(); container.RegisterType(); @@ -287,8 +286,7 @@ public void EnumerableTests_Resolve_PreserveOrder_Parent() public void EnumerableTests_Resolve_PreserveOrder_Parent_Lazy() { IStashboxContainer container = new StashboxContainer(config => - config.WithEnumerableOrderRule(Rules.EnumerableOrder.PreserveOrder) - .WithParentContainerResolution()); + config.WithEnumerableOrderRule(Rules.EnumerableOrder.PreserveOrder)); container.RegisterType(); container.RegisterType(); @@ -307,8 +305,7 @@ public void EnumerableTests_Resolve_PreserveOrder_Parent_Lazy() public void EnumerableTests_Resolve_PreserveOrder_Parent_Func() { IStashboxContainer container = new StashboxContainer(config => - config.WithEnumerableOrderRule(Rules.EnumerableOrder.PreserveOrder) - .WithParentContainerResolution()); + config.WithEnumerableOrderRule(Rules.EnumerableOrder.PreserveOrder)); container.RegisterType(); container.RegisterType(); diff --git a/src/stashbox/BuildUp/GenericTypeObjectBuilder.cs b/src/stashbox/BuildUp/GenericTypeObjectBuilder.cs index 825cc9c9..46b73bb8 100644 --- a/src/stashbox/BuildUp/GenericTypeObjectBuilder.cs +++ b/src/stashbox/BuildUp/GenericTypeObjectBuilder.cs @@ -1,12 +1,11 @@ using Stashbox.BuildUp.Expressions; using Stashbox.Entity; -using Stashbox.Exceptions; using Stashbox.Infrastructure; using Stashbox.Infrastructure.ContainerExtension; using Stashbox.Registration; -using Stashbox.Utils; using System; using System.Linq.Expressions; +using Stashbox.Infrastructure.Registration; namespace Stashbox.BuildUp { @@ -17,6 +16,7 @@ internal class GenericTypeObjectBuilder : ObjectBuilderBase private readonly IMetaInfoProvider metaInfoProvider; private readonly IContainerContext containerContext; private readonly IExpressionBuilder expressionBuilder; + private readonly bool isDecorator; public GenericTypeObjectBuilder(RegistrationContextData registrationContextData, IContainerContext containerContext, IMetaInfoProvider metaInfoProvider, IContainerExtensionManager containerExtensionManager, @@ -28,32 +28,27 @@ public GenericTypeObjectBuilder(RegistrationContextData registrationContextData, this.containerContext = containerContext; this.containerExtensionManager = containerExtensionManager; this.expressionBuilder = expressionBuilder; + this.isDecorator = isDecorator; } protected override Expression GetExpressionInternal(ResolutionInfo resolutionInfo, Type resolveType) { var genericType = this.metaInfoProvider.TypeTo.MakeGenericType(resolveType.GetGenericArguments()); - var typeInfo = new TypeInformation - { - Type = resolveType, - DependencyName = NameGenerator.GetRegistrationName(resolveType, genericType) - }; - - this.RegisterConcreteGenericType(resolveType, genericType); - - var registration = this.containerContext.RegistrationRepository.GetRegistrationOrDefault(typeInfo); - if (registration == null) - throw new ResolutionFailedException(genericType.FullName); - + var registration = this.RegisterConcreteGenericType(resolveType, genericType); return registration.GetExpression(resolutionInfo, resolveType); } - private void RegisterConcreteGenericType(Type resolveType, Type genericType) + private IServiceRegistration RegisterConcreteGenericType(Type resolveType, Type genericType) { var registrationContext = new ScopedRegistrationContext(resolveType, genericType, this.containerContext, this.expressionBuilder, this.containerExtensionManager); var newData = this.registrationContextData.CreateCopy(); newData.Name = null; - registrationContext.InitFromScope(newData); + + if (!this.isDecorator) return registrationContext.InitFromScope(newData); + + var registration = registrationContext.CreateRegistration(newData, this.isDecorator); + this.containerContext.DecoratorRepository.AddDecorator(resolveType, registration); + return registration; } } } diff --git a/src/stashbox/BuildUp/ObjectBuilderBase.cs b/src/stashbox/BuildUp/ObjectBuilderBase.cs index bc46fb79..73deab5c 100644 --- a/src/stashbox/BuildUp/ObjectBuilderBase.cs +++ b/src/stashbox/BuildUp/ObjectBuilderBase.cs @@ -18,19 +18,32 @@ protected ObjectBuilderBase(IContainerContext containerContext, bool isDecorator public Expression GetExpression(ResolutionInfo resolutionInfo, Type resolveType) { - if (this.isDecorator) return this.GetExpressionInternal(resolutionInfo, resolveType); + if (this.isDecorator || resolutionInfo.CurrentlyDecoratingTypes.Contains(resolveType)) + return this.GetExpressionInternal(resolutionInfo, resolveType); var decorators = this.containerContext.DecoratorRepository.GetDecoratorsOrDefault(resolveType); - if (decorators == null) return this.GetExpressionInternal(resolutionInfo, resolveType); + if (decorators == null) + { + if (resolveType.IsClosedGenericType()) + { + decorators = this.containerContext.DecoratorRepository.GetDecoratorsOrDefault(resolveType.GetGenericTypeDefinition()); + if (decorators == null) + return this.GetExpressionInternal(resolutionInfo, resolveType); + } + else + return this.GetExpressionInternal(resolutionInfo, resolveType); + } + resolutionInfo.CurrentlyDecoratingTypes.Add(resolveType); var expression = this.GetExpressionInternal(resolutionInfo, resolveType); foreach (var decoratorRegistration in decorators) { - resolutionInfo.ExpressionOverrides.AddOrUpdate(resolveType, expression, (oldValue,newValue) => newValue); + resolutionInfo.ExpressionOverrides.AddOrUpdate(resolveType, expression, (oldValue, newValue) => newValue); expression = decoratorRegistration.GetExpression(resolutionInfo, resolveType); } + resolutionInfo.CurrentlyDecoratingTypes.Remove(resolveType); return expression; } diff --git a/src/stashbox/BuildUp/Resolution/ParentContainerResolver.cs b/src/stashbox/BuildUp/Resolution/ParentContainerResolver.cs index 26d5bcba..02564d4c 100644 --- a/src/stashbox/BuildUp/Resolution/ParentContainerResolver.cs +++ b/src/stashbox/BuildUp/Resolution/ParentContainerResolver.cs @@ -10,8 +10,7 @@ internal class ParentContainerResolver : Resolver public override bool SupportsMany => true; public override bool CanUseForResolution(IContainerContext containerContext, TypeInformation typeInfo) => - containerContext.ContainerConfigurator.ContainerConfiguration.ParentContainerResolutionEnabled && - containerContext.Container.ParentContainer != null && containerContext.Container.ParentContainer.CanResolve(typeInfo.Type, typeInfo.DependencyName); + containerContext.Container.ParentContainer != null && containerContext.Container.ParentContainer.CanResolve(typeInfo.Type, typeInfo.DependencyName); public override Expression GetExpression(IContainerContext containerContext, TypeInformation typeInfo, ResolutionInfo resolutionInfo) => containerContext.Container.ParentContainer.ContainerContext.ResolutionStrategy diff --git a/src/stashbox/Configuration/ContainerConfiguration.cs b/src/stashbox/Configuration/ContainerConfiguration.cs index 4bbbc5d2..e2a45bb8 100644 --- a/src/stashbox/Configuration/ContainerConfiguration.cs +++ b/src/stashbox/Configuration/ContainerConfiguration.cs @@ -25,12 +25,7 @@ internal static ContainerConfiguration DefaultContainerConfiguration() /// If it's set to true the container will track transient objects for disposal. /// public bool TrackTransientsForDisposalEnabled { get; internal set; } - - /// - /// If it's set to true the container will use the parent container for missing registration resolution. - /// - public bool ParentContainerResolutionEnabled { get; internal set; } - + /// /// If it's set to true the container will track circular dependencies in the dependency graph and will throw an exception if any of it found. /// @@ -79,7 +74,6 @@ internal static ContainerConfiguration DefaultContainerConfiguration() internal ContainerConfiguration() { this.TrackTransientsForDisposalEnabled = false; - this.ParentContainerResolutionEnabled = false; this.CircularDependencyTrackingEnabled = false; this.OptionalAndDefaultValueInjectionEnabled = false; this.UnknownTypeResolutionEnabled = false; diff --git a/src/stashbox/Configuration/ContainerConfigurator.cs b/src/stashbox/Configuration/ContainerConfigurator.cs index d56e3f32..8f9ae396 100644 --- a/src/stashbox/Configuration/ContainerConfigurator.cs +++ b/src/stashbox/Configuration/ContainerConfigurator.cs @@ -28,13 +28,6 @@ public IContainerConfigurator WithDisposableTransientTracking() return this; } - /// - public IContainerConfigurator WithParentContainerResolution() - { - this.ContainerConfiguration.ParentContainerResolutionEnabled = true; - return this; - } - /// public IContainerConfigurator WithCircularDependencyTracking() { diff --git a/src/stashbox/Entity/ResolutionInfo.cs b/src/stashbox/Entity/ResolutionInfo.cs index 9639250a..1d4c2f90 100644 --- a/src/stashbox/Entity/ResolutionInfo.cs +++ b/src/stashbox/Entity/ResolutionInfo.cs @@ -23,12 +23,15 @@ public class ResolutionInfo internal HashSet CircularDependencyBarrier { get; } - internal ConcurrentTree ExpressionOverrides { get; } + internal AvlTree ExpressionOverrides { get; } + + internal HashSet CurrentlyDecoratingTypes { get; } internal ResolutionInfo() { this.CircularDependencyBarrier = new HashSet(); - this.ExpressionOverrides = new ConcurrentTree(); + this.ExpressionOverrides = new AvlTree(); + this.CurrentlyDecoratingTypes = new HashSet(); } } } \ No newline at end of file diff --git a/src/stashbox/Infrastructure/IContainerConfigurator.cs b/src/stashbox/Infrastructure/IContainerConfigurator.cs index 44097d0e..37fd7a52 100644 --- a/src/stashbox/Infrastructure/IContainerConfigurator.cs +++ b/src/stashbox/Infrastructure/IContainerConfigurator.cs @@ -22,12 +22,6 @@ public interface IContainerConfigurator /// The container configurator. IContainerConfigurator WithDisposableTransientTracking(); - /// - /// Enables the resolution through the parent container. - /// - /// The container configurator. - IContainerConfigurator WithParentContainerResolution(); - /// /// Enables the circular dependency tracking. /// diff --git a/src/stashbox/Registration/RegistrationContextBase.cs b/src/stashbox/Registration/RegistrationContextBase.cs index 2e6de781..7b9f8c20 100644 --- a/src/stashbox/Registration/RegistrationContextBase.cs +++ b/src/stashbox/Registration/RegistrationContextBase.cs @@ -35,11 +35,13 @@ public RegistrationContextBase(Type typeFrom, Type typeTo, IContainerContext con this.expressionBuilder = expressionBuilder; } - protected void CompleteRegistration(bool update = false) + protected IServiceRegistration CompleteRegistration(bool update = false) { var registration = this.CreateServiceRegistration(); this.ContainerContext.RegistrationRepository.AddOrUpdateRegistration(this.TypeFrom, this.RegistrationContextData.Name, update, registration); this.CompleteScopeManagement(update, registration.LifetimeManager, registration.ObjectBuilder); + + return registration; } protected IServiceRegistration CreateServiceRegistration(bool isDecorator = false) diff --git a/src/stashbox/Registration/ScopedRegistrationContext.cs b/src/stashbox/Registration/ScopedRegistrationContext.cs index eb7c2ffc..aa3b7359 100644 --- a/src/stashbox/Registration/ScopedRegistrationContext.cs +++ b/src/stashbox/Registration/ScopedRegistrationContext.cs @@ -2,6 +2,7 @@ using Stashbox.Infrastructure; using Stashbox.Infrastructure.ContainerExtension; using System; +using Stashbox.Infrastructure.Registration; namespace Stashbox.Registration { @@ -12,10 +13,16 @@ public ScopedRegistrationContext(Type typeFrom, Type typeTo, IContainerContext c : base(typeFrom, typeTo, containerContext, expressionBuilder, containerExtensionManager) { } - public void InitFromScope(RegistrationContextData scopeData) + public IServiceRegistration InitFromScope(RegistrationContextData scopeData) { base.RegistrationContextData = scopeData; - base.CompleteRegistration(); + return base.CompleteRegistration(); + } + + public IServiceRegistration CreateRegistration(RegistrationContextData scopeData, bool isDecorator = false) + { + base.RegistrationContextData = scopeData; + return base.CreateServiceRegistration(isDecorator); } } } diff --git a/src/stashbox/Utils/AvlTree.cs b/src/stashbox/Utils/AvlTree.cs index 7efeb4d3..51fecec5 100644 --- a/src/stashbox/Utils/AvlTree.cs +++ b/src/stashbox/Utils/AvlTree.cs @@ -4,6 +4,34 @@ namespace Stashbox.Utils { + internal class AvlTree : IEnumerable + { + private AvlTree repository; + + public AvlTree() + { + this.repository = new AvlTree(); + } + + public TValue GetOrDefault(TKey key) + { + var hash = key.GetHashCode(); + return this.repository.GetOrDefault(hash); + } + + public void AddOrUpdate(TKey key, TValue value, + Func updateDelegate = null) + { + var hash = key.GetHashCode(); + this.repository = this.repository.AddOrUpdate(hash, value, updateDelegate); + } + + IEnumerator IEnumerable.GetEnumerator() => this.repository.GetEnumerator(); + + public IEnumerator GetEnumerator() => this.repository.GetEnumerator(); + } + + internal class AvlTree : IEnumerable { private static readonly AvlTree Empty = new AvlTree(); @@ -38,10 +66,8 @@ private AvlTree(int hash, TValue value) public AvlTree() { } - public virtual AvlTree AddOrUpdate(int key, TValue value, Func updateDelegate = null) - { - return this.Add(key, value, updateDelegate); - } + public AvlTree AddOrUpdate(int key, TValue value, Func updateDelegate = null) => + this.Add(key, value, updateDelegate); public TValue GetOrDefault(int key) {