diff --git a/src/Lamar/IoC/Enumerables/ArrayInstance.cs b/src/Lamar/IoC/Enumerables/ArrayInstance.cs index 0f7ca3a5..ac92b01f 100644 --- a/src/Lamar/IoC/Enumerables/ArrayInstance.cs +++ b/src/Lamar/IoC/Enumerables/ArrayInstance.cs @@ -63,7 +63,13 @@ protected override IEnumerable createPlan(ServiceGraph services) } else { - Elements = services.FindAll(typeof(T)); + // MS DI's IServiceProvider.GetServices(T) (and by extension T[] resolution) returns + // only non-keyed registrations; keyed registrations are looked up explicitly via + // GetKeyedService(T, key). Match that here so a keyed-mirror registration of the + // same service type doesn't end up as a T[] element. Otherwise inlining the + // mirror's Singleton via QuickResolve invokes the mirror's factory, which calls + // sp.GetServices(T) again and recursively re-enters codegen — stack overflow. + Elements = services.FindAll(typeof(T)).Where(x => !x.IsKeyedService).ToArray(); } return Elements; diff --git a/src/Lamar/IoC/Enumerables/ListInstance.cs b/src/Lamar/IoC/Enumerables/ListInstance.cs index 494c723d..ef68c386 100644 --- a/src/Lamar/IoC/Enumerables/ListInstance.cs +++ b/src/Lamar/IoC/Enumerables/ListInstance.cs @@ -56,7 +56,13 @@ protected override IEnumerable createPlan(ServiceGraph services) } else { - Elements = services.FindAll(typeof(T)); + // MS DI's IServiceProvider.GetServices(T) returns only non-keyed registrations; + // keyed registrations are looked up explicitly via GetKeyedService(T, key). Match + // that here so a keyed-mirror registration of the same service type doesn't end up + // as an IEnumerable element. Otherwise inlining the mirror's Singleton via + // QuickResolve invokes the mirror's factory, which calls sp.GetServices(T) again + // and recursively re-enters ListInstance/ArrayInstance code-gen — stack overflow. + Elements = services.FindAll(typeof(T)).Where(x => !x.IsKeyedService).ToArray(); } return Elements;