diff --git a/src/stashbox.tests/BuildExtensionManagerTests.cs b/src/stashbox.tests/BuildExtensionManagerTests.cs index 5dfd13a0..31a4cf11 100644 --- a/src/stashbox.tests/BuildExtensionManagerTests.cs +++ b/src/stashbox.tests/BuildExtensionManagerTests.cs @@ -3,6 +3,7 @@ using Stashbox.Entity; using Stashbox.Infrastructure.ContainerExtension; using System; +using Stashbox.Infrastructure.Registration; namespace Stashbox.Tests { @@ -20,7 +21,7 @@ public void BuildExtensionManagerTests_AddPostBuildExtension() container.RegisterType(context => context.WithFactory(() => obj)); post.Setup(p => p.PostBuild(obj, container.ContainerContext, It.IsAny(), - It.IsAny(), null)).Returns(obj).Verifiable(); + It.IsAny(), It.IsAny())).Returns(obj).Verifiable(); var inst = container.Resolve(typeof(object)); post.Verify(p => p.Initialize(container.ContainerContext)); @@ -40,7 +41,7 @@ public void BuildExtensionManagerTests_AddPostBuildExtension_WithDefaultReg() bool called = false; post.Setup(p => p.PostBuild(It.IsAny(), container.ContainerContext, It.IsAny(), - It.IsAny(), null)).Returns(It.IsAny()).Callback(() => called = true).Verifiable(); + It.IsAny(), It.IsAny())).Returns(It.IsAny()).Callback(() => called = true).Verifiable(); var inst = container.Resolve(); Assert.IsTrue(called); @@ -60,8 +61,7 @@ public void BuildExtensionManagerTests_AddRegistrationBuildExtension() container.RegisterExtension(post.Object); container.RegisterInstanceAs(new object()); post.Verify(p => p.Initialize(container.ContainerContext)); - post.Verify(p => p.OnRegistration(container.ContainerContext, - It.IsAny(), It.IsAny(), null)); + post.Verify(p => p.OnRegistration(container.ContainerContext, It.IsAny())); } post.Verify(p => p.CleanUp()); @@ -83,8 +83,7 @@ public void BuildExtensionManagerTests_CreateCopy() child.RegisterInstanceAs(new object()); post2.Verify(p => p.Initialize(child.ContainerContext)); - post2.Verify(p => p.OnRegistration(child.ContainerContext, - It.IsAny(), It.IsAny(), null)); + post2.Verify(p => p.OnRegistration(child.ContainerContext, It.IsAny())); } post2.Verify(p => p.CleanUp()); diff --git a/src/stashbox.tests/DisposeTests.cs b/src/stashbox.tests/DisposeTests.cs index 13f1a7b2..1a50dc53 100644 --- a/src/stashbox.tests/DisposeTests.cs +++ b/src/stashbox.tests/DisposeTests.cs @@ -186,7 +186,7 @@ public void DisposeTests_Scoped() container.RegisterScoped(); container.RegisterScoped(); - container.RegisterScoped(); + container.RegisterScoped("test"); test = container.Resolve(); test2 = container.Resolve(); @@ -194,7 +194,7 @@ public void DisposeTests_Scoped() using (var child = container.BeginScope()) { - test4 = child.Resolve(); + test4 = (ITest1)child.Resolve(typeof(ITest1), "test"); test5 = child.Resolve(); test6 = child.Resolve(); } @@ -232,6 +232,29 @@ public void DisposeTests_PutInScope_RootScope() Assert.IsTrue(test.Disposed); } + [TestMethod] + public void DisposeTests_PutInScope_RootScope_WithoutDispose() + { + var test = new Test1(); + using (IStashboxContainer container = new StashboxContainer()) + { + container.RegisterType(); + container.RegisterType(); + + container.PutInstanceInScope(test, true); + + var test1 = container.Resolve(); + var test2 = container.Resolve(typeof(ITest2)); + var test3 = container.Resolve(); + + Assert.AreSame(test, test1); + Assert.AreSame(test, ((ITest2)test2).Test1); + Assert.AreSame(test, test3.Test1); + } + + Assert.IsFalse(test.Disposed); + } + [TestMethod] public void DisposeTests_PutInScope_Scoped() { diff --git a/src/stashbox.tests/GenericTests.cs b/src/stashbox.tests/GenericTests.cs index aeba0de2..c82b1719 100644 --- a/src/stashbox.tests/GenericTests.cs +++ b/src/stashbox.tests/GenericTests.cs @@ -156,8 +156,8 @@ public void GenericTests_Resolve_Constraint_Multiple() { using (var container = new StashboxContainer()) { - container.RegisterType(typeof(IConstraintTest<>), typeof(ConstraintTest<>)); container.RegisterType(typeof(IConstraintTest<>), typeof(ConstraintTest2<>)); + container.RegisterType(typeof(IConstraintTest<>), typeof(ConstraintTest<>)); var inst = container.Resolve>(); Assert.IsInstanceOfType(inst, typeof(ConstraintTest)); @@ -189,16 +189,35 @@ public void GenericTests_Resolve_Constraint_Constructor() } } - public interface Constraint { } + [TestMethod] + public void GenericTests_Resolve_Constraint_Pick_RightImpl() + { + using (var container = new StashboxContainer()) + { + container.RegisterType(typeof(IConstraintTest<>), typeof(ConstraintTest2<>)); + container.RegisterType(typeof(IConstraintTest<>), typeof(ConstraintTest3<>)); + + var inst = container.Resolve>(); + Assert.IsInstanceOfType(inst, typeof(ConstraintTest3)); + } + } + + public interface IConstraint { } + + public interface IConstraint1 { } public interface IConstraintTest { } public class ConstraintTest : IConstraintTest { } - public class ConstraintTest2 : IConstraintTest where T : Constraint { } + public class ConstraintTest2 : IConstraintTest where T : IConstraint { } + + public class ConstraintTest3 : IConstraintTest where T : IConstraint1 { } public class ConstraintArgument { } + public class ConstraintArgument1 : IConstraint1 { } + public class ConstraintTest3 { public IConstraintTest Test { get; set; } diff --git a/src/stashbox.tests/InjectionMemberTests.cs b/src/stashbox.tests/InjectionMemberTests.cs index 1e47bb81..b523657a 100644 --- a/src/stashbox.tests/InjectionMemberTests.cs +++ b/src/stashbox.tests/InjectionMemberTests.cs @@ -26,7 +26,21 @@ public void InjectionMemberTests_Resolve() } [TestMethod] - public void InjectionMemberTests_BuildUp() + public void InjectionMemberTests_Resolve_WithoutRegistered() + { + var container = new StashboxContainer(); + var test1 = new Test1(); + container.WireUpAs(test1); + + var inst = container.Resolve(); + + Assert.IsNotNull(inst); + Assert.IsNull(inst.Test); + Assert.IsNull(((Test1)inst).TestFieldProperty); + } + + [TestMethod] + public void InjectionMemberTests_WireUp() { using (var container = new StashboxContainer()) { diff --git a/src/stashbox.tests/LazyTests.cs b/src/stashbox.tests/LazyTests.cs index 4d805dbf..547f90de 100644 --- a/src/stashbox.tests/LazyTests.cs +++ b/src/stashbox.tests/LazyTests.cs @@ -70,7 +70,7 @@ public void LazyTests_Resolve_Enumerable_Null() { var container = new StashboxContainer(); var inst = container.Resolve>>(); - + Assert.AreEqual(0, inst.Value.Count()); } @@ -101,7 +101,7 @@ public void LazyTests_Resolve_ConstructorDependency_Null() [TestMethod] public void LazyTests_Resolve_Circular() { - var container = new StashboxContainer(config => + var container = new StashboxContainer(config => config.WithCircularDependencyTracking() .WithCircularDependencyWithLazy()); @@ -116,24 +116,22 @@ public void LazyTests_Resolve_Circular() } [TestMethod] - public void LazyTests_Resolve_Circular_FromCache() + public void LazyTests_Resolve_Circular_Evaluate() { var container = new StashboxContainer(config => config.WithCircularDependencyTracking() .WithCircularDependencyWithLazy()); - container.RegisterSingleton(); - container.RegisterSingleton(); + container.RegisterType(); + container.RegisterType(); var inst1 = container.Resolve(); - var inst2 = container.Resolve(); - Assert.AreSame(container.Resolve(), inst1.Dep.Value); - Assert.AreSame(container.Resolve(), inst2.Dep.Value); + Assert.IsNotNull(inst1.Dep.Value.Dep.Value.Dep.Value.Dep); } [TestMethod] - public void LazyTests_Resolve_Circular_Evaluate() + public void LazyTests_Resolve_Circular_Evaluate_Singleton() { var container = new StashboxContainer(config => config.WithCircularDependencyTracking() @@ -144,15 +142,13 @@ public void LazyTests_Resolve_Circular_Evaluate() var inst1 = container.Resolve(); - var val = inst1.Dep.Value.Dep.Value.Dep.Value.Dep; - - Assert.IsNotNull(val); + Assert.IsNotNull(inst1.Dep.Value.Dep.Value.Dep.Value.Dep); } [TestMethod] public void LazyTests_Resolve_IEnumerable_Circular() { - var container = new StashboxContainer(config => + var container = new StashboxContainer(config => config.WithCircularDependencyTracking() .WithCircularDependencyWithLazy()); diff --git a/src/stashbox.tests/StandardResolveTests.cs b/src/stashbox.tests/StandardResolveTests.cs index 42d37928..8cee1e9c 100644 --- a/src/stashbox.tests/StandardResolveTests.cs +++ b/src/stashbox.tests/StandardResolveTests.cs @@ -168,7 +168,7 @@ public void StandardResolveTests_Resolve_Parallel() container.RegisterType(context => context.WithName(i.ToString())); container.RegisterType(context => context.WithName($"ITest3{i.ToString()}")); var test33 = container.Resolve($"ITest3{i.ToString()}"); - var test11 = container.Resolve(i.ToString()); + var test11 = container.Resolve(typeof(ITest1), i.ToString()); Assert.IsNotNull(test33); Assert.IsNotNull(test11); diff --git a/src/stashbox.tests/WireUpTests.cs b/src/stashbox.tests/WireUpTests.cs index 033026a0..952559a0 100644 --- a/src/stashbox.tests/WireUpTests.cs +++ b/src/stashbox.tests/WireUpTests.cs @@ -27,7 +27,26 @@ public void WireUp_Multiple() } [TestMethod] - public void InjectionMemberTests_WireUp() + public void WireUp_Multiple_Named() + { + using (var container = new StashboxContainer()) + { + var test1 = new Test(); + container.WireUpAs(test1, "test1"); + + var test2 = new Test(); + container.WireUpAs(test2, "test2"); + + var inst = container.Resolve("test1"); + var inst2 = container.Resolve("test2"); + + Assert.AreSame(test1, inst); + Assert.AreSame(test2, inst2); + } + } + + [TestMethod] + public void WireUpTests_InjectionMember() { using (var container = new StashboxContainer()) { @@ -49,7 +68,7 @@ public void InjectionMemberTests_WireUp() } [TestMethod] - public void InjectionMemberTests_WireUp_ServiceUpdated() + public void WireUpTests_InjectionMember_ServiceUpdated() { using (var container = new StashboxContainer()) { @@ -73,7 +92,7 @@ public void InjectionMemberTests_WireUp_ServiceUpdated() } [TestMethod] - public void InjectionMemberTests_WireUp_WithoutService() + public void WireUpTests_InjectionMember_WithoutService() { using (var container = new StashboxContainer()) { @@ -90,7 +109,7 @@ public void InjectionMemberTests_WireUp_WithoutService() } [TestMethod] - public void InjectionMemberTests_WireUp_WithoutService_NonGeneric() + public void WireUpTests_WithoutService_NonGeneric() { using (var container = new StashboxContainer()) { diff --git a/src/stashbox/BuildExtensionManager.cs b/src/stashbox/BuildExtensionManager.cs index 48524c58..0ab80276 100644 --- a/src/stashbox/BuildExtensionManager.cs +++ b/src/stashbox/BuildExtensionManager.cs @@ -4,6 +4,7 @@ using System.Linq; using Stashbox.Utils; using System; +using Stashbox.Infrastructure.Registration; namespace Stashbox { @@ -24,22 +25,23 @@ public void AddExtension(IContainerExtension containerExtension) { if (containerExtension is IPostBuildExtension) this.HasPostBuildExtensions = true; - else + + if (containerExtension is IRegistrationExtension) this.HasRegistrationExtensions = true; this.repository.Add(containerExtension); } public object ExecutePostBuildExtensions(object instance, IContainerContext containerContext, ResolutionInfo resolutionInfo, - Type resolveType, InjectionParameter[] injectionParameters = null) => - this.repository.OfType().Aggregate(instance, (current, extension) => extension.PostBuild(current, containerContext, resolutionInfo, resolveType, injectionParameters)); + IServiceRegistration serviceRegistration, Type requestedType) => + this.repository.OfType().Aggregate(instance, (current, extension) => extension.PostBuild(current, containerContext, resolutionInfo, serviceRegistration, requestedType)); - public void ExecuteOnRegistrationExtensions(IContainerContext containerContext, Type typeTo, Type typeFrom, InjectionParameter[] injectionParameters = null) + public void ExecuteOnRegistrationExtensions(IContainerContext containerContext, IServiceRegistration serviceRegistration) { if (!this.HasRegistrationExtensions) return; foreach (var extension in this.repository.OfType()) - extension.OnRegistration(containerContext, typeTo, typeFrom, injectionParameters); + extension.OnRegistration(containerContext, serviceRegistration); } public IContainerExtensionManager CreateCopy() diff --git a/src/stashbox/BuildUp/Expressions/ExpressionBuilder.cs b/src/stashbox/BuildUp/Expressions/ExpressionBuilder.cs index 1174ea2c..5b81a5fa 100644 --- a/src/stashbox/BuildUp/Expressions/ExpressionBuilder.cs +++ b/src/stashbox/BuildUp/Expressions/ExpressionBuilder.cs @@ -96,7 +96,7 @@ private ResolutionConstructor CreateResolutionConstructor(IServiceRegistration s resolutionInfo, serviceRegistration.MetaInformation.GetTypeInformationForParameter(parameter), serviceRegistration.RegistrationContext.InjectionParameters); - parameterExpressions[i] = expression ?? throw new ResolutionFailedException(serviceRegistration.ImplementationType, + parameterExpressions[i] = expression ?? throw new ResolutionFailedException(serviceRegistration.ImplementationType, $"Constructor {constructor}, unresolvable parameter: ({parameter.ParameterType}){parameter.Name}"); } @@ -171,7 +171,7 @@ private Expression CreatePostWorkExpressionIfAny(IServiceRegistration serviceReg if (this.containerExtensionManager.HasPostBuildExtensions) { var call = Expression.Call(Expression.Constant(this.containerExtensionManager), Constants.BuildExtensionMethod, newVariable, Expression.Constant(this.containerContext), - Expression.Constant(resolutionInfo), Expression.Constant(serviceType), Expression.Constant(serviceRegistration.RegistrationContext.InjectionParameters, typeof(InjectionParameter[]))); + Expression.Constant(resolutionInfo), Expression.Constant(serviceRegistration), Expression.Constant(serviceType)); block.Add(Expression.Assign(newVariable, Expression.Convert(call, serviceType))); } diff --git a/src/stashbox/BuildUp/Resolution/LazyResolver.cs b/src/stashbox/BuildUp/Resolution/LazyResolver.cs index 2c90cd6f..54f70505 100644 --- a/src/stashbox/BuildUp/Resolution/LazyResolver.cs +++ b/src/stashbox/BuildUp/Resolution/LazyResolver.cs @@ -31,7 +31,7 @@ public override Expression GetExpression(IContainerContext containerContext, Typ if (registration != null) return !containerContext.ContainerConfigurator.ContainerConfiguration.CircularDependenciesWithLazyEnabled ? Expression.New(lazyConstructor, Expression.Lambda(registration.GetExpression(resolutionInfo, lazyArgumentInfo.Type))) : - this.CreateLazyExpressionCall(registration, lazyArgumentInfo.Type, lazyConstructor, resolutionInfo); + CreateLazyExpressionCall(registration, lazyArgumentInfo.Type, lazyConstructor, resolutionInfo); var expression = this.resolverSelector.GetResolverExpression(containerContext, lazyArgumentInfo, resolutionInfo); @@ -55,7 +55,7 @@ public override Expression[] GetExpressions(IContainerContext containerContext, regExpressions[i] = Expression.New(lazyConstructor, Expression.Lambda(registrations[i].Value.GetExpression(resolutionInfo, lazyArgumentInfo.Type))); else - regExpressions[i] = this.CreateLazyExpressionCall(registrations[i].Value, lazyArgumentInfo.Type, lazyConstructor, resolutionInfo); + regExpressions[i] = CreateLazyExpressionCall(registrations[i].Value, lazyArgumentInfo.Type, lazyConstructor, resolutionInfo); return regExpressions; } @@ -72,13 +72,12 @@ public override Expression[] GetExpressions(IContainerContext containerContext, return expressions; } - private Expression CreateLazyExpressionCall(IServiceRegistration serviceRegistration, Type type, ConstructorInfo constructor, ResolutionInfo resolutionInfo) + private static Expression CreateLazyExpressionCall(IServiceRegistration serviceRegistration, Type type, ConstructorInfo constructor, ResolutionInfo resolutionInfo) { - var delegateCache = new DelegateCache(type); - var callExpression = Expression.Call(Expression.Constant(delegateCache), - DelegateCacheMethod, + var callExpression = Expression.Call(DelegateCacheMethod, Expression.Constant(serviceRegistration), Expression.Constant(resolutionInfo), + Expression.Constant(type), Expression.NewArrayInit(typeof(object), resolutionInfo.ParameterExpressions?.OfType() ?? new Expression[] { })); @@ -89,27 +88,12 @@ private Expression CreateLazyExpressionCall(IServiceRegistration serviceRegistra public override bool CanUseForResolution(IContainerContext containerContext, TypeInformation typeInfo, ResolutionInfo resolutionInfo) => typeInfo.Type.IsClosedGenericType() && typeInfo.Type.GetGenericTypeDefinition() == typeof(Lazy<>); - private static readonly MethodInfo DelegateCacheMethod = typeof(DelegateCache).GetSingleMethod("CreateLazyDelegate"); + private static readonly MethodInfo DelegateCacheMethod = typeof(LazyResolver).GetSingleMethod(nameof(CreateLazyDelegate), true); - private class DelegateCache + private static object CreateLazyDelegate(IServiceRegistration serviceRegistration, ResolutionInfo resolutionInfo, Type type, object[] arguments) { - private readonly Type type; - private Func cache; - - public DelegateCache(Type type) - { - this.type = type; - } - - public object CreateLazyDelegate(IServiceRegistration serviceRegistration, ResolutionInfo resolutionInfo, object[] arguments) - { - if (this.cache != null) - return this.cache(resolutionInfo.ResolutionScope).DynamicInvoke(arguments); - - var expr = serviceRegistration.GetExpression(resolutionInfo, this.type); - this.cache = Expression.Lambda(expr, resolutionInfo.ParameterExpressions).CompileDelegate(Constants.ScopeExpression); - return this.cache(resolutionInfo.ResolutionScope).DynamicInvoke(arguments); - } + var expr = serviceRegistration.GetExpression(resolutionInfo, type); + return Expression.Lambda(expr, resolutionInfo.ParameterExpressions).CompileDelegate(Constants.ScopeExpression)(resolutionInfo.ResolutionScope).DynamicInvoke(arguments); } } } diff --git a/src/stashbox/Constants.cs b/src/stashbox/Constants.cs index b41aa2bd..e3b32f3f 100644 --- a/src/stashbox/Constants.cs +++ b/src/stashbox/Constants.cs @@ -16,31 +16,31 @@ public static class Constants /// /// The scope parameter expression. /// - public static ParameterExpression ScopeExpression = Expression.Parameter(typeof(IResolutionScope)); + public static readonly ParameterExpression ScopeExpression = Expression.Parameter(typeof(IResolutionScope)); - internal static MethodInfo AddDisposalMethod = typeof(IResolutionScope).GetSingleMethod("AddDisposableTracking"); + internal static readonly MethodInfo AddDisposalMethod = typeof(IResolutionScope).GetSingleMethod("AddDisposableTracking"); - internal static MethodInfo AddWithFinalizerMethod = typeof(IResolutionScope).GetSingleMethod("AddWithFinalizer"); + internal static readonly MethodInfo AddWithFinalizerMethod = typeof(IResolutionScope).GetSingleMethod("AddWithFinalizer"); - internal static MethodInfo BuildExtensionMethod = typeof(IContainerExtensionManager).GetSingleMethod("ExecutePostBuildExtensions"); + internal static readonly MethodInfo BuildExtensionMethod = typeof(IContainerExtensionManager).GetSingleMethod("ExecutePostBuildExtensions"); - internal static MethodInfo GetScopedValueMethod = typeof(ScopedLifetime).GetSingleMethod("GetScopedValue", true); + internal static readonly MethodInfo GetScopedInstanceMethod = typeof(IResolutionScope).GetSingleMethod("GetScopedInstanceOrDefault"); - internal static MethodInfo GetScopedInstanceMethod = typeof(IResolutionScope).GetSingleMethod("GetScopedInstanceOrDefault"); + internal static readonly Type DisposableType = typeof(IDisposable); - internal static Type DisposableType = typeof(IDisposable); + internal static readonly Type FuncType = typeof(Func<>); - internal static Type FuncType = typeof(Func<>); + internal static readonly Type ResolverType = typeof(IDependencyResolver); - internal static Type ResolverType = typeof(IDependencyResolver); + internal static readonly Type[] EmptyTypes = new Type[0]; - internal static Type[] EmptyTypes = new Type[0]; + internal static readonly Type ObjectType = typeof(object); - internal static Type ObjectType = typeof(object); + internal static readonly ConstructorInfo ObjectConstructor = ObjectType.GetConstructor(EmptyTypes); - internal static ConstructorInfo ObjectConstructor = ObjectType.GetConstructor(EmptyTypes); + internal static readonly Type CompositionRootType = typeof(ICompositionRoot); - internal static Type CompositionRootType = typeof(ICompositionRoot); + internal static readonly Type DependencyAttributeType = typeof(Attributes.DependencyAttribute); internal const MethodImplOptions Inline = (MethodImplOptions)256; } diff --git a/src/stashbox/Entity/TypeInformation.cs b/src/stashbox/Entity/TypeInformation.cs index c9406b55..ece73a4d 100644 --- a/src/stashbox/Entity/TypeInformation.cs +++ b/src/stashbox/Entity/TypeInformation.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Stashbox.Attributes; namespace Stashbox.Entity @@ -26,7 +27,7 @@ public class TypeInformation /// /// Custom attributes of the dependency. /// - public Attribute[] CustomAttributes { get; internal set; } + public IEnumerable CustomAttributes { get; internal set; } /// /// The variable name of the dependency. diff --git a/src/stashbox/Infrastructure/ContainerExtension/IContainerExtensionManager.cs b/src/stashbox/Infrastructure/ContainerExtension/IContainerExtensionManager.cs index b9df7e34..cc8f71b5 100644 --- a/src/stashbox/Infrastructure/ContainerExtension/IContainerExtensionManager.cs +++ b/src/stashbox/Infrastructure/ContainerExtension/IContainerExtensionManager.cs @@ -1,5 +1,6 @@ -using Stashbox.Entity; -using System; +using System; +using Stashbox.Entity; +using Stashbox.Infrastructure.Registration; namespace Stashbox.Infrastructure.ContainerExtension { @@ -7,8 +8,8 @@ internal interface IContainerExtensionManager { void AddExtension(IContainerExtension containerExtension); object ExecutePostBuildExtensions(object instance, IContainerContext containerContext, ResolutionInfo resolutionInfo, - Type resolveType, InjectionParameter[] injectionParameters = null); - void ExecuteOnRegistrationExtensions(IContainerContext containerContext, Type typeTo, Type typeFrom, InjectionParameter[] injectionParameters = null); + IServiceRegistration serviceRegistration, Type requestedType); + void ExecuteOnRegistrationExtensions(IContainerContext containerContext, IServiceRegistration serviceRegistration); IContainerExtensionManager CreateCopy(); void ReinitalizeExtensions(IContainerContext containerContext); bool HasPostBuildExtensions { get; } diff --git a/src/stashbox/Infrastructure/ContainerExtension/IPostBuildExtension.cs b/src/stashbox/Infrastructure/ContainerExtension/IPostBuildExtension.cs index 87325385..552d355f 100644 --- a/src/stashbox/Infrastructure/ContainerExtension/IPostBuildExtension.cs +++ b/src/stashbox/Infrastructure/ContainerExtension/IPostBuildExtension.cs @@ -1,5 +1,6 @@ using System; using Stashbox.Entity; +using Stashbox.Infrastructure.Registration; namespace Stashbox.Infrastructure.ContainerExtension { @@ -14,10 +15,10 @@ public interface IPostBuildExtension : IContainerExtension /// The resolved object. /// The of the /// Information about the actual resolution. - /// The type information of the resolved type. - /// The injection parameters. + /// The service registration. + /// The requested type. /// The extended object. object PostBuild(object instance, IContainerContext containerContext, ResolutionInfo resolutionInfo, - Type resolveType, InjectionParameter[] injectionParameters = null); + IServiceRegistration serviceRegistration, Type requestedType); } } diff --git a/src/stashbox/Infrastructure/ContainerExtension/IRegistrationExtension.cs b/src/stashbox/Infrastructure/ContainerExtension/IRegistrationExtension.cs index 676cdf7b..9204e779 100644 --- a/src/stashbox/Infrastructure/ContainerExtension/IRegistrationExtension.cs +++ b/src/stashbox/Infrastructure/ContainerExtension/IRegistrationExtension.cs @@ -1,5 +1,4 @@ -using Stashbox.Entity; -using System; +using Stashbox.Infrastructure.Registration; namespace Stashbox.Infrastructure.ContainerExtension { @@ -12,9 +11,7 @@ public interface IRegistrationExtension : IContainerExtension /// Executes when a new service being registered. /// /// The of the - /// The implementation type. - /// The interface type. - /// The injection parameters. - void OnRegistration(IContainerContext containerContext, Type typeTo, Type typeFrom, InjectionParameter[] injectionParameters = null); + /// The service registration. + void OnRegistration(IContainerContext containerContext, IServiceRegistration serviceRegistration); } } diff --git a/src/stashbox/Lifetime/ScopedLifetime.cs b/src/stashbox/Lifetime/ScopedLifetime.cs index e35f2bc1..56a50fd1 100644 --- a/src/stashbox/Lifetime/ScopedLifetime.cs +++ b/src/stashbox/Lifetime/ScopedLifetime.cs @@ -1,5 +1,6 @@ using System; using System.Linq.Expressions; +using System.Reflection; using Stashbox.Entity; using Stashbox.Infrastructure; using Stashbox.Infrastructure.Registration; @@ -15,6 +16,8 @@ public class ScopedLifetime : LifetimeBase private readonly object syncObject = new object(); private readonly object scopeId = new object(); + private static readonly MethodInfo GetScopedValueMethod = typeof(ScopedLifetime).GetSingleMethod(nameof(GetScopedValue), true); + /// public override ILifetime Create() => new ScopedLifetime(); @@ -32,7 +35,7 @@ public override Expression GetExpression(IServiceRegistration serviceRegistratio var factory = expr.CompileDelegate(Constants.ScopeExpression); - var method = Constants.GetScopedValueMethod.MakeGenericMethod(resolveType); + var method = GetScopedValueMethod.MakeGenericMethod(resolveType); this.expression = Expression.Call(method, Constants.ScopeExpression, diff --git a/src/stashbox/MetaInfo/MetaInformation.cs b/src/stashbox/MetaInfo/MetaInformation.cs index 40d66b52..a4682fb3 100644 --- a/src/stashbox/MetaInfo/MetaInformation.cs +++ b/src/stashbox/MetaInfo/MetaInformation.cs @@ -56,7 +56,7 @@ public bool ValidateGenericContraints(Type typeForValidation) var length = typeInfo.GenericTypeArguments.Length; for (var i = 0; i < length; i++) - if (this.GenericTypeConstraints.ContainsKey(i) && !this.GenericTypeConstraints[i].Contains(typeInfo.GenericTypeArguments[i])) + if (this.GenericTypeConstraints.ContainsKey(i) && !this.GenericTypeConstraints[i].Any(constraint => typeInfo.GenericTypeArguments[i].Implements(constraint))) return false; return true; @@ -67,19 +67,22 @@ public bool ValidateGenericContraints(Type typeForValidation) /// /// The parameter info. /// The converted type info. - public TypeInformation GetTypeInformationForParameter(ParameterInfo parameter) => - new TypeInformation + public TypeInformation GetTypeInformationForParameter(ParameterInfo parameter) + { + var customAttributes = parameter.GetCustomAttributes(); + var dependencyAttribute = parameter.GetCustomAttribute(); + return new TypeInformation { Type = parameter.ParameterType, - DependencyName = parameter.GetCustomAttribute()?.Name, - HasDependencyAttribute = parameter.GetCustomAttribute() != null, + DependencyName = dependencyAttribute?.Name, + HasDependencyAttribute = dependencyAttribute != null, ParentType = this.type, - CustomAttributes = parameter.GetCustomAttributes()?.ToArray(), + CustomAttributes = customAttributes, ParameterName = parameter.Name, HasDefaultValue = parameter.HasDefaultValue(), DefaultValue = parameter.DefaultValue }; - + } private void AddConstructors(IEnumerable constructors) => this.Constructors = constructors @@ -106,7 +109,6 @@ private TypeInformation[] FillParameters(ParameterInfo[] parameters) for (int i = 0; i < length; i++) types[i] = this.GetTypeInformationForParameter(parameters[i]); - return types; } diff --git a/src/stashbox/Registration/DecoratorRepository.cs b/src/stashbox/Registration/DecoratorRepository.cs index 6171c3cf..50d9a9c3 100644 --- a/src/stashbox/Registration/DecoratorRepository.cs +++ b/src/stashbox/Registration/DecoratorRepository.cs @@ -17,7 +17,7 @@ public class DecoratorRepository : IDecoratorRepository /// public DecoratorRepository() { - this.repository = ConcurrentTree>.Create(); + this.repository = new ConcurrentTree>(); } /// diff --git a/src/stashbox/Registration/ServiceRegistration.cs b/src/stashbox/Registration/ServiceRegistration.cs index afac44b4..d6bb3d3c 100644 --- a/src/stashbox/Registration/ServiceRegistration.cs +++ b/src/stashbox/Registration/ServiceRegistration.cs @@ -54,11 +54,12 @@ internal ServiceRegistration(Type serviceType, Type implementationType, IContain } /// - public bool IsUsableForCurrentContext(TypeInformation typeInfo) => this.RegistrationContext.TargetTypeCondition == null && this.RegistrationContext.ResolutionCondition == null && (this.RegistrationContext.AttributeConditions == null || !this.RegistrationContext.AttributeConditions.Any()) || - this.RegistrationContext.TargetTypeCondition != null && typeInfo.ParentType != null && this.RegistrationContext.TargetTypeCondition == typeInfo.ParentType || - this.RegistrationContext.AttributeConditions != null && typeInfo.CustomAttributes != null && - this.RegistrationContext.AttributeConditions.Intersect(typeInfo.CustomAttributes.Select(attribute => attribute.GetType())).Any() || - this.RegistrationContext.ResolutionCondition != null && this.RegistrationContext.ResolutionCondition(typeInfo); + public bool IsUsableForCurrentContext(TypeInformation typeInfo) => + this.RegistrationContext.TargetTypeCondition == null && this.RegistrationContext.ResolutionCondition == null && (this.RegistrationContext.AttributeConditions == null || !this.RegistrationContext.AttributeConditions.Any()) || + this.RegistrationContext.TargetTypeCondition != null && typeInfo.ParentType != null && this.RegistrationContext.TargetTypeCondition == typeInfo.ParentType || + this.RegistrationContext.AttributeConditions != null && typeInfo.CustomAttributes != null && + this.RegistrationContext.AttributeConditions.Intersect(typeInfo.CustomAttributes.Select(attribute => attribute.GetType())).Any() || + this.RegistrationContext.ResolutionCondition != null && this.RegistrationContext.ResolutionCondition(typeInfo); /// public bool HasCondition => this.RegistrationContext.TargetTypeCondition != null || this.RegistrationContext.ResolutionCondition != null || diff --git a/src/stashbox/Registration/ServiceRegistrator.cs b/src/stashbox/Registration/ServiceRegistrator.cs index 7973cf21..d23ce3f6 100644 --- a/src/stashbox/Registration/ServiceRegistrator.cs +++ b/src/stashbox/Registration/ServiceRegistrator.cs @@ -59,8 +59,7 @@ public IStashboxContainer Register(IRegistrationContextMeta registrationContextM if (replace) this.containerContext.DelegateRepository.InvalidateDelegateCache(); - this.containerExtensionManager.ExecuteOnRegistrationExtensions(this.containerContext, registrationContextMeta.ServiceType, - registrationContextMeta.ImplementationType, registrationContextMeta.Context.InjectionParameters); + this.containerExtensionManager.ExecuteOnRegistrationExtensions(this.containerContext, registration); return this.containerContext.Container; } @@ -81,8 +80,7 @@ public IStashboxContainer ReMap(IRegistrationContextMeta registrationContextMeta this.containerContext.DelegateRepository.InvalidateDelegateCache(); - this.containerExtensionManager.ExecuteOnRegistrationExtensions(this.containerContext, registrationContextMeta.ServiceType, - registrationContextMeta.ImplementationType, registrationContextMeta.Context.InjectionParameters); + this.containerExtensionManager.ExecuteOnRegistrationExtensions(this.containerContext, registration); return this.containerContext.Container; } diff --git a/src/stashbox/ResolutionScope.cs b/src/stashbox/ResolutionScope.cs index 5e42fd00..c3014a4f 100644 --- a/src/stashbox/ResolutionScope.cs +++ b/src/stashbox/ResolutionScope.cs @@ -16,7 +16,7 @@ internal class ResolutionScope : ResolutionScopeBase, IDependencyResolver private readonly IServiceRegistrator serviceRegistrator; private readonly IExpressionBuilder expressionBuilder; private readonly IResolutionScope rootScope; - + public ResolutionScope(IActivationContext activationContext, IServiceRegistrator serviceRegistrator, IExpressionBuilder expressionBuilder, IResolutionScope rootScope) { @@ -25,57 +25,57 @@ public ResolutionScope(IActivationContext activationContext, IServiceRegistrator this.expressionBuilder = expressionBuilder; this.rootScope = rootScope; } - + public TKey Resolve(bool nullResultAllowed = false) => (TKey)this.activationContext.Activate(typeof(TKey), this, nullResultAllowed); - + public object Resolve(Type typeFrom, bool nullResultAllowed = false) => this.activationContext.Activate(typeFrom, this, nullResultAllowed); - + public TKey Resolve(object name, bool nullResultAllowed = false) => (TKey)this.activationContext.Activate(typeof(TKey), this, name, nullResultAllowed); - + public object Resolve(Type typeFrom, object name, bool nullResultAllowed = false) => this.activationContext.Activate(typeFrom, this, name, nullResultAllowed); - + public IEnumerable ResolveAll() => (IEnumerable)this.activationContext.Activate(typeof(IEnumerable), this); - + public IEnumerable ResolveAll(Type typeFrom) => (IEnumerable)this.activationContext.Activate(typeof(IEnumerable<>).MakeGenericType(typeFrom), this); - + public Delegate ResolveFactory(Type typeFrom, object name = null, bool nullResultAllowed = false, params Type[] parameterTypes) => this.activationContext.ActivateFactory(typeFrom, parameterTypes, this, name, nullResultAllowed); - + public Func ResolveFactory(object name = null, bool nullResultAllowed = false) => this.ResolveFactory(typeof(TService), name, nullResultAllowed) as Func; - + public Func ResolveFactory(object name = null, bool nullResultAllowed = false) => this.ResolveFactory(typeof(TService), name, nullResultAllowed, typeof(T1)) as Func; - + public Func ResolveFactory(object name = null, bool nullResultAllowed = false) => this.ResolveFactory(typeof(TService), name, nullResultAllowed, typeof(T1), typeof(T2)) as Func; - + public Func ResolveFactory(object name = null, bool nullResultAllowed = false) => this.ResolveFactory(typeof(TService), name, nullResultAllowed, typeof(T1), typeof(T2), typeof(T3)) as Func; - + public Func ResolveFactory(object name = null, bool nullResultAllowed = false) => this.ResolveFactory(typeof(TService), name, nullResultAllowed, typeof(T1), typeof(T2), typeof(T3), typeof(T4)) as Func; - + public IDependencyResolver BeginScope() => new ResolutionScope(this.activationContext, this.serviceRegistrator, this.expressionBuilder, this.rootScope); - + public IDependencyResolver PutInstanceInScope(TFrom instance, bool withoutDisposalTracking = false) => this.PutInstanceInScope(typeof(TFrom), instance, withoutDisposalTracking); - + public IDependencyResolver PutInstanceInScope(Type typeFrom, object instance, bool withoutDisposalTracking = false) { Shield.EnsureNotNull(typeFrom, nameof(typeFrom)); Shield.EnsureNotNull(instance, nameof(instance)); base.AddScopedInstance(typeFrom, instance); - if (!withoutDisposalTracking && instance is IDisposable) - base.AddDisposableTracking((IDisposable)instance); + if (!withoutDisposalTracking && instance is IDisposable disposable) + base.AddDisposableTracking(disposable); return this; } diff --git a/src/stashbox/ResolutionScopeBase.cs b/src/stashbox/ResolutionScopeBase.cs index ff4f571c..f754e04d 100644 --- a/src/stashbox/ResolutionScopeBase.cs +++ b/src/stashbox/ResolutionScopeBase.cs @@ -112,7 +112,7 @@ protected virtual void Dispose(bool disposing) var root = this.rootItem; while (!ReferenceEquals(root, DisposableItem.Empty)) { - root.Item?.Dispose(); + root.Item.Dispose(); root = root.Next; } } diff --git a/src/stashbox/StashboxContainer.FuncRegistrator.cs b/src/stashbox/StashboxContainer.FuncRegistrator.cs index 4df2beb6..9a2d998d 100644 --- a/src/stashbox/StashboxContainer.FuncRegistrator.cs +++ b/src/stashbox/StashboxContainer.FuncRegistrator.cs @@ -39,7 +39,7 @@ private IDependencyRegistrator RegisterFuncInternal(Delegate factory, Type facto data, false, false); this.registrationRepository.AddOrUpdateRegistration(registration, name ?? (object)internalFactoryType, false, false); - this.containerExtensionManager.ExecuteOnRegistrationExtensions(this.ContainerContext, factoryType, internalFactoryType); + this.containerExtensionManager.ExecuteOnRegistrationExtensions(this.ContainerContext, registration); return this; } } diff --git a/src/stashbox/StashboxContainer.Registrator.cs b/src/stashbox/StashboxContainer.Registrator.cs index 8ff1b9b8..0b4b689b 100644 --- a/src/stashbox/StashboxContainer.Registrator.cs +++ b/src/stashbox/StashboxContainer.Registrator.cs @@ -149,7 +149,7 @@ private void WireUpInternal(object instance, object keyName, Type typeFrom, Type data, false, !withoutDisposalTracking); this.registrationRepository.AddOrUpdateRegistration(registration, keyName ?? typeTo, false, false); - this.containerExtensionManager.ExecuteOnRegistrationExtensions(this.ContainerContext, typeTo, typeFrom); + this.containerExtensionManager.ExecuteOnRegistrationExtensions(this.ContainerContext, registration); } } } diff --git a/src/stashbox/StashboxContainer.Resolver.cs b/src/stashbox/StashboxContainer.Resolver.cs index 54e23510..fc9c1551 100644 --- a/src/stashbox/StashboxContainer.Resolver.cs +++ b/src/stashbox/StashboxContainer.Resolver.cs @@ -69,8 +69,8 @@ public IDependencyResolver PutInstanceInScope(Type typeFrom, object instance, bo Shield.EnsureNotNull(instance, nameof(instance)); base.AddScopedInstance(typeFrom, instance); - if (!withoutDisposalTracking && instance is IDisposable) - base.AddDisposableTracking((IDisposable)instance); + if (!withoutDisposalTracking && instance is IDisposable disposable) + base.AddDisposableTracking(disposable); return this; } diff --git a/src/stashbox/Utils/AvlTree.cs b/src/stashbox/Utils/AvlTree.cs index 79dc064d..7f45a225 100644 --- a/src/stashbox/Utils/AvlTree.cs +++ b/src/stashbox/Utils/AvlTree.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Stashbox.Utils { @@ -44,6 +45,7 @@ public AvlTree AddOrUpdate(int key, TValue value, Func AddOrUpdate(int key, TValue value, out bool updated, Func updateDelegate = null) => this.Add(key, value, updateDelegate, out updated); + [MethodImpl(Constants.Inline)] public TValue GetOrDefault(int key) { var node = this; diff --git a/src/stashbox/Utils/ConcurrentTree.cs b/src/stashbox/Utils/ConcurrentTree.cs index 15312b5b..f3f5c14d 100644 --- a/src/stashbox/Utils/ConcurrentTree.cs +++ b/src/stashbox/Utils/ConcurrentTree.cs @@ -12,12 +12,6 @@ namespace Stashbox.Utils /// The type of the value. public class ConcurrentTree : IEnumerable { - /// - /// Static factory method. - /// - /// A new tree instance - public static ConcurrentTree Create() => new ConcurrentTree(); - private AvlTreeKeyValue repository; /// @@ -116,12 +110,6 @@ public ConcurrentTree AddOrUpdate(int hash, TKey key, TValue value /// The type of the value. public class ConcurrentTree : IEnumerable { - /// - /// Static factory method. - /// - /// A new tree instance - public static ConcurrentTree Create() => new ConcurrentTree(); - private AvlTree repository; ///