diff --git a/src/LightInject.Tests/LazyTests.cs b/src/LightInject.Tests/LazyTests.cs index 6c65728d..177004d5 100644 --- a/src/LightInject.Tests/LazyTests.cs +++ b/src/LightInject.Tests/LazyTests.cs @@ -55,6 +55,43 @@ public void CanGetInstance_LazyForUnknownService_ReturnsFalse(string serviceName Assert.False(container.CanGetInstance(typeof(Lazy), serviceName)); } + [Fact] + public void GetInstance_LazyForUnknownNamedService_ThrowsInvalidOperationException() + { + var container = CreateContainer(); + + container.Register(); + + var anotherLazyFoo = container.GetInstance>("AnotherFoo"); + + Assert.Throws(() => anotherLazyFoo.Value); + } + + [Fact] + public void GetInstance_LazyForUnknownNamedServiceWithFallback_ReturnsLazyThatResolvesNamedService() + { + var container = CreateContainer(); + + container.RegisterFallback((serviceType, serviceName) => serviceType == typeof(IFoo) && serviceName == "AnotherFoo", request => new Foo()); + + var anotherLazyFoo = container.GetInstance>("AnotherFoo"); + + Assert.IsType(anotherLazyFoo.Value); + } + + [Fact] + public void GetInstance_LazyForKnownNamedService_ReturnsLazyThatResolvesNamedService() + { + var container = CreateContainer(); + + container.Register(); + container.Register("AnotherFoo"); + + var anotherLazyFoo = container.GetInstance>("AnotherFoo"); + + Assert.IsType(anotherLazyFoo.Value); + } + [Fact] public void GetInstance_NamedService_ReturnsLazyThatResolvesNamedService() { diff --git a/src/LightInject/LightInject.cs b/src/LightInject/LightInject.cs index 1c4adc7d..a9cecdf8 100644 --- a/src/LightInject/LightInject.cs +++ b/src/LightInject/LightInject.cs @@ -4488,7 +4488,7 @@ private Action CreateEmitMethodForUnknownService(Type serviceType, str } else if (serviceType.IsLazy()) { - emitter = CreateEmitMethodBasedOnLazyServiceRequest(serviceType); + emitter = CreateEmitMethodBasedOnLazyServiceRequest(serviceType, serviceName); } else if (serviceType.IsFuncWithParameters()) { @@ -4667,27 +4667,55 @@ private Action CreateEmitMethodForReadOnlyCollectionServiceRequest(Typ }; } - private Action CreateEmitMethodBasedOnLazyServiceRequest(Type serviceType) + private Action CreateEmitMethodBasedOnLazyServiceRequest(Type serviceType, string serviceName) { var returnType = serviceType.GetTypeInfo().GenericTypeArguments.Last(); - var createScopedLazyMethod = LazyHelper.CreateScopedLazyMethod.MakeGenericMethod(returnType); - return e => + + if (string.IsNullOrWhiteSpace(serviceName)) { - e.PushConstant(constants.Add(this), typeof(ServiceContainer)); + var createScopedLazyMethod = LazyHelper.CreateScopedLazyMethod.MakeGenericMethod(returnType); + return e => + { + e.PushConstant(constants.Add(this), typeof(ServiceContainer)); - int scopeManagerIndex = CreateScopeManagerIndex(); + int scopeManagerIndex = CreateScopeManagerIndex(); - // Push the scope into the stack - e.PushArgument(1); + // Push the scope into the stack + e.PushArgument(1); - // Push the scope manager into the stack. - e.PushConstant(scopeManagerIndex, typeof(IScopeManager)); + // Push the scope manager into the stack. + e.PushConstant(scopeManagerIndex, typeof(IScopeManager)); - // Get the scope - e.Emit(OpCodes.Call, ScopeLoader.GetThisOrCurrentScopeMethod); + // Get the scope + e.Emit(OpCodes.Call, ScopeLoader.GetThisOrCurrentScopeMethod); - e.Emit(OpCodes.Call, createScopedLazyMethod); - }; + e.Emit(OpCodes.Call, createScopedLazyMethod); + }; + } + else + { + var createNamedScopedLazyMethod = LazyHelper.CreateNamedScopedLazyMethod.MakeGenericMethod(returnType); + return e => + { + e.PushConstant(constants.Add(this), typeof(ServiceContainer)); + + int scopeManagerIndex = CreateScopeManagerIndex(); + + // Push the scope into the stack + e.PushArgument(1); + + // Push the scope manager into the stack. + e.PushConstant(scopeManagerIndex, typeof(IScopeManager)); + + // Get the scope + e.Emit(OpCodes.Call, ScopeLoader.GetThisOrCurrentScopeMethod); + + // Push serviceName + e.Emit(OpCodes.Ldstr, serviceName); + + e.Emit(OpCodes.Call, createNamedScopedLazyMethod); + }; + } } private ThreadSafeDictionary GetOpenGenericServiceRegistrations(Type openGenericServiceType) @@ -8959,17 +8987,23 @@ internal static class LazyHelper { public static readonly MethodInfo CreateScopedLazyMethod; + public static readonly MethodInfo CreateNamedScopedLazyMethod; + public static readonly MethodInfo CreateScopedLazyFromDelegateMethod; static LazyHelper() { CreateScopedLazyMethod = typeof(LazyHelper).GetTypeInfo().GetDeclaredMethod("CreateScopedLazy"); + CreateNamedScopedLazyMethod = typeof(LazyHelper).GetTypeInfo().GetDeclaredMethod("CreateNamedScopedLazy"); CreateScopedLazyFromDelegateMethod = typeof(LazyHelper).GetTypeInfo().GetDeclaredMethod("CreateScopedLazyFromDelegate"); } public static Lazy CreateScopedLazy(ServiceContainer serviceContainer, Scope scope) => new Lazy(() => (T)serviceContainer.GetInstance(typeof(T), scope)); + public static Lazy CreateNamedScopedLazy(ServiceContainer serviceContainer, Scope scope, string serviceName) + => new Lazy(() => (T)serviceContainer.GetInstance(typeof(T), scope, serviceName)); + public static Lazy CreateScopedLazyFromDelegate(GetInstanceDelegate getInstanceDelegate, object[] constants, Scope scope) => new Lazy(() => (T)getInstanceDelegate(constants, scope)); }