@@ -9,7 +9,7 @@ namespace SimpleInjector.Internals
99
1010 internal sealed class GenericRegistrationEntry : IRegistrationEntry
1111 {
12- private readonly List < IProducerProvider > providers = new List < IProducerProvider > ( ) ;
12+ private readonly List < IProducerProvider > providers = new ( ) ;
1313 private readonly Container container ;
1414
1515 internal GenericRegistrationEntry ( Container container )
@@ -21,7 +21,8 @@ private interface IProducerProvider
2121 {
2222 bool IsConditional { get ; }
2323
24- bool AppliesToAllClosedServiceTypes { get ; }
24+ // The first call to this method can be costly to perform.
25+ bool GetAppliesToAllClosedServiceTypes ( ) ;
2526
2627 Type ServiceType { get ; }
2728
@@ -70,9 +71,12 @@ public void AddGeneric(
7071
7172 this . ThrowWhenProviderToRegisterOverlapsWithExistingProvider ( provider ) ;
7273
73- if ( provider . AppliesToAllClosedServiceTypes && this . container . Options . AllowOverridingRegistrations )
74+ if ( this . container . Options . AllowOverridingRegistrations )
7475 {
75- this . providers . RemoveAll ( p => p . AppliesToAllClosedServiceTypes ) ;
76+ if ( provider . GetAppliesToAllClosedServiceTypes ( ) )
77+ {
78+ this . providers . RemoveAll ( p => p . GetAppliesToAllClosedServiceTypes ( ) ) ;
79+ }
7680 }
7781
7882 this . providers . Add ( provider ) ;
@@ -178,21 +182,19 @@ private void ThrowWhenConditionalIsRegisteredInOverridingMode(InstanceProducer p
178182 private void ThrowWhenConditionalIsRegisteredInOverridingMode (
179183 OpenGenericToInstanceProducerProvider provider )
180184 {
181- if ( ! provider . AppliesToAllClosedServiceTypes
182- && this . container . Options . AllowOverridingRegistrations )
185+ if ( this . providers . Count > 0
186+ && this . container . Options . AllowOverridingRegistrations
187+ && ! provider . GetAppliesToAllClosedServiceTypes ( ) )
183188 {
184- if ( this . providers . Count > 0 )
189+ if ( provider . Predicate != null )
185190 {
186- if ( provider . Predicate != null )
187- {
188- throw new NotSupportedException (
189- StringResources . MakingConditionalRegistrationsInOverridingModeIsNotSupported ( ) ) ;
190- }
191- else
192- {
193- throw new NotSupportedException (
194- StringResources . MakingRegistrationsWithTypeConstraintsInOverridingModeIsNotSupported ( ) ) ;
195- }
191+ throw new NotSupportedException (
192+ StringResources . MakingConditionalRegistrationsInOverridingModeIsNotSupported ( ) ) ;
193+ }
194+ else
195+ {
196+ throw new NotSupportedException (
197+ StringResources . MakingRegistrationsWithTypeConstraintsInOverridingModeIsNotSupported ( ) ) ;
196198 }
197199 }
198200 }
@@ -201,14 +203,14 @@ private void ThrowWhenProviderToRegisterOverlapsWithExistingProvider(
201203 OpenGenericToInstanceProducerProvider providerToRegister )
202204 {
203205 bool providerToRegisterIsSuperset =
204- providerToRegister . AppliesToAllClosedServiceTypes && this . providers . Count > 0 ;
206+ this . providers . Count > 0 && providerToRegister . GetAppliesToAllClosedServiceTypes ( ) ;
205207
206208 // A provider with AppliesToAllClosedServiceTypes true will always have an ImplementationType,
207209 // because the property will always be false for providers with a factory.
208210 Type providerImplementationType = providerToRegister . ImplementationType ! ;
209211
210- bool isReplacement = providerToRegister . AppliesToAllClosedServiceTypes
211- && this . container . Options . AllowOverridingRegistrations ;
212+ bool isReplacement = this . container . Options . AllowOverridingRegistrations
213+ && providerToRegister . GetAppliesToAllClosedServiceTypes ( ) ;
212214
213215 // A provider is a superset of the providerToRegister when it can be applied to ALL generic
214216 // types that the providerToRegister can be applied to as well.
@@ -230,13 +232,11 @@ private IEnumerable<IProducerProvider> GetSupersetProvidersFor(Type implementati
230232 from provider in this . providers
231233 where implementationType != null
232234 where provider . ImplementationType != null
233- where provider . AppliesToAllClosedServiceTypes
234- || provider . ImplementationType == implementationType
235+ where provider . ImplementationType == implementationType || provider . GetAppliesToAllClosedServiceTypes ( )
235236 select provider ;
236237
237238 private static InvalidOperationException GetAnOverlappingGenericRegistrationExistsException (
238- IProducerProvider providerToRegister , IProducerProvider overlappingProvider ) =>
239- new InvalidOperationException (
239+ IProducerProvider providerToRegister , IProducerProvider overlappingProvider ) => new (
240240 StringResources . AnOverlappingRegistrationExists (
241241 providerToRegister . ServiceType ,
242242 // ImplementationType will never be null, because providers can never be overlapping when they
@@ -287,7 +287,7 @@ public ClosedToInstanceProducerProvider(InstanceProducer producer)
287287 }
288288
289289 public bool IsConditional => this . producer . IsConditional ;
290- public bool AppliesToAllClosedServiceTypes => false ;
290+ public bool GetAppliesToAllClosedServiceTypes ( ) => false ;
291291 public Type ServiceType => this . producer . ServiceType ;
292292 public Type ? ImplementationType => this . producer . Registration . ImplementationType ;
293293 public IEnumerable < InstanceProducer > CurrentProducers => Enumerable . Repeat ( this . producer , 1 ) ;
@@ -311,14 +311,14 @@ private sealed class OpenGenericToInstanceProducerProvider : IProducerProvider
311311 {
312312 internal readonly Predicate < PredicateContext > ? Predicate ;
313313
314- private readonly Dictionary < object , InstanceProducer > cache =
315- new Dictionary < object , InstanceProducer > ( ) ;
316- private readonly Dictionary < Type , Registration > registrationCache =
317- new Dictionary < Type , Registration > ( ) ;
314+ private readonly Dictionary < object , InstanceProducer > cache = new ( ) ;
315+ private readonly Dictionary < Type , Registration > registrationCache = new ( ) ;
318316
319317 private readonly Lifestyle lifestyle ;
320318 private readonly Container container ;
321319
320+ private bool ? appliesToAllClosedServiceTypes ;
321+
322322 internal OpenGenericToInstanceProducerProvider (
323323 Type serviceType ,
324324 Type implementationType ,
@@ -332,11 +332,6 @@ internal OpenGenericToInstanceProducerProvider(
332332 this . lifestyle = lifestyle ;
333333 this . Predicate = predicate ;
334334 this . container = container ;
335-
336- // We cache the result of this method, because this is a really heavy operation.
337- // Not caching it can dramatically influence the performance of the registration process.
338- this . AppliesToAllClosedServiceTypes =
339- this . RegistrationAppliesToAllClosedServiceTypes ( implementationType ) ;
340335 }
341336
342337 internal OpenGenericToInstanceProducerProvider (
@@ -351,11 +346,26 @@ internal OpenGenericToInstanceProducerProvider(
351346 this . lifestyle = lifestyle ;
352347 this . Predicate = predicate ;
353348 this . container = container ;
354- this . AppliesToAllClosedServiceTypes = false ;
349+ this . appliesToAllClosedServiceTypes = false ;
355350 }
356351
357352 public bool IsConditional => this . Predicate != null ;
358- public bool AppliesToAllClosedServiceTypes { get ; }
353+
354+ // I turned this former property into a method call to make it more obvious that this is can be
355+ // a very costly operation (which can also throw first-chance exceptions).
356+ public bool GetAppliesToAllClosedServiceTypes ( )
357+ {
358+ if ( this . appliesToAllClosedServiceTypes is null )
359+ {
360+ // We cache the result of this method. Not caching it can dramatically influence the
361+ // performance of the registration process.
362+ this . appliesToAllClosedServiceTypes =
363+ this . RegistrationAppliesToAllClosedServiceTypes ( this . ImplementationType ! ) ;
364+ }
365+
366+ return this . appliesToAllClosedServiceTypes . Value ;
367+ }
368+
359369 public Type ServiceType { get ; }
360370 public Type ? ImplementationType { get ; }
361371 public Func < TypeFactoryContext , Type > ImplementationTypeFactory { get ; }
@@ -462,7 +472,7 @@ private InstanceProducer GetProducer(PredicateContext context)
462472 }
463473
464474 private InstanceProducer CreateNewProducerFor ( PredicateContext context ) =>
465- new InstanceProducer ( context . ServiceType , this . GetRegistration ( context ) , this . Predicate ) ;
475+ new ( context . ServiceType , this . GetRegistration ( context ) , this . Predicate ) ;
466476
467477 private Registration GetRegistration ( PredicateContext context )
468478 {
0 commit comments