@@ -10,13 +10,17 @@ namespace SimpleInjector.Internals
1010 internal sealed class GenericRegistrationEntry : IRegistrationEntry
1111 {
1212 private readonly List < IProducerProvider > providers = new ( ) ;
13- private readonly Container container ;
13+ private readonly ContainerOptions options ;
1414
1515 internal GenericRegistrationEntry ( Container container )
1616 {
17- this . container = container ;
17+ this . options = container . Options ;
1818 }
1919
20+ private Container Container => this . options . Container ;
21+ private bool AllowOverridingRegistrations => this . options . AllowOverridingRegistrations ;
22+ private bool IsEmpty => this . providers . Count == 0 ;
23+
2024 private interface IProducerProvider
2125 {
2226 bool IsConditional { get ; }
@@ -43,14 +47,18 @@ private interface IProducerProvider
4347
4448 public void Add ( InstanceProducer producer )
4549 {
46- this . container . ThrowWhenContainerIsLockedOrDisposed ( ) ;
50+ this . Container . ThrowWhenContainerIsLockedOrDisposed ( ) ;
4751
4852 this . ThrowWhenConditionalIsRegisteredInOverridingMode ( producer ) ;
49- this . ThrowWhenOverlappingRegistrationsExist ( producer ) ;
5053
51- if ( this . container . Options . AllowOverridingRegistrations )
54+ if ( ! this . AllowOverridingRegistrations )
55+ {
56+ this . ThrowWhenOverlappingRegistrationsExist ( producer ) ; // O(n) operation
57+ }
58+
59+ if ( this . AllowOverridingRegistrations )
5260 {
53- this . providers . RemoveAll ( p => p . ServiceType == producer . ServiceType ) ;
61+ this . providers . RemoveAll ( p => p . ServiceType == producer . ServiceType ) ; // O(n) operation
5462 }
5563
5664 this . providers . Add ( new ClosedToInstanceProducerProvider ( producer ) ) ;
@@ -62,16 +70,16 @@ public void AddGeneric(
6270 Lifestyle lifestyle ,
6371 Predicate < PredicateContext > ? predicate )
6472 {
65- this . container . ThrowWhenContainerIsLockedOrDisposed ( ) ;
73+ this . Container . ThrowWhenContainerIsLockedOrDisposed ( ) ;
6674
6775 var provider = new OpenGenericToInstanceProducerProvider (
68- serviceType , implementationType , lifestyle , predicate , this . container ) ;
76+ serviceType , implementationType , lifestyle , predicate , this . Container ) ;
6977
7078 this . ThrowWhenConditionalIsRegisteredInOverridingMode ( provider ) ;
7179
7280 this . ThrowWhenProviderToRegisterOverlapsWithExistingProvider ( provider ) ;
7381
74- if ( this . container . Options . AllowOverridingRegistrations )
82+ if ( this . AllowOverridingRegistrations )
7583 {
7684 if ( provider . GetAppliesToAllClosedServiceTypes ( ) )
7785 {
@@ -88,10 +96,10 @@ public void Add(
8896 Lifestyle lifestyle ,
8997 Predicate < PredicateContext > ? predicate )
9098 {
91- this . container . ThrowWhenContainerIsLockedOrDisposed ( ) ;
99+ this . Container . ThrowWhenContainerIsLockedOrDisposed ( ) ;
92100
93101 var provider = new OpenGenericToInstanceProducerProvider (
94- serviceType , implementationTypeFactory , lifestyle , predicate , this . container ) ;
102+ serviceType , implementationTypeFactory , lifestyle , predicate , this . Container ) ;
95103
96104 this . ThrowWhenConditionalIsRegisteredInOverridingMode ( provider ) ;
97105
@@ -121,9 +129,11 @@ public void Add(
121129 }
122130 }
123131
132+ // This method is only called when we're about to throw an exception.
124133 public int GetNumberOfConditionalRegistrationsFor ( Type serviceType ) =>
125134 this . GetConditionalProvidersThatMatchType ( serviceType ) . Count ( ) ;
126135
136+ // This method is only called when we're about to throw an exception.
127137 private IEnumerable < IProducerProvider > GetConditionalProvidersThatMatchType ( Type serviceType ) =>
128138 from provider in this . providers
129139 where provider . IsConditional
@@ -132,47 +142,50 @@ where provider.MatchesServiceType(serviceType)
132142
133143 private void ThrowWhenOverlappingRegistrationsExist ( InstanceProducer producerToRegister )
134144 {
135- if ( ! this . container . Options . AllowOverridingRegistrations )
136- {
137- var overlappingProviders =
138- from provider in this . providers
139- where provider . OverlapsWith ( producerToRegister )
140- select provider ;
145+ var overlappingProvider = this . GetFirstOverlappingProvider ( producerToRegister ) ;
141146
142- if ( overlappingProviders . Any ( ) )
147+ if ( overlappingProvider != null )
148+ {
149+ if ( overlappingProvider . ServiceType . IsGenericTypeDefinition ( ) )
143150 {
144- var overlappingProvider = overlappingProviders . First ( ) ;
151+ // An overlapping provider will always have an ImplementationType, because providers
152+ // with a factory will never be overlapping.
153+ Type implementationType = overlappingProvider . ImplementationType ! ;
154+
155+ throw new InvalidOperationException (
156+ StringResources . RegistrationForClosedServiceTypeOverlapsWithOpenGenericRegistration (
157+ producerToRegister . ServiceType ,
158+ implementationType ) ) ;
159+ }
145160
146- if ( overlappingProvider . ServiceType . IsGenericTypeDefinition ( ) )
147- {
148- // An overlapping provider will always have an ImplementationType, because providers
149- // with a factory will never be overlapping.
150- Type implementationType = overlappingProvider . ImplementationType ! ;
151-
152- throw new InvalidOperationException (
153- StringResources . RegistrationForClosedServiceTypeOverlapsWithOpenGenericRegistration (
154- producerToRegister . ServiceType ,
155- implementationType ) ) ;
156- }
161+ bool eitherOneRegistrationIsConditional =
162+ overlappingProvider . IsConditional != producerToRegister . IsConditional ;
157163
158- bool eitherOneRegistrationIsConditional =
159- overlappingProvider . IsConditional != producerToRegister . IsConditional ;
164+ throw eitherOneRegistrationIsConditional
165+ ? GetAnOverlappingGenericRegistrationExistsException (
166+ new ClosedToInstanceProducerProvider ( producerToRegister ) ,
167+ overlappingProvider )
168+ : new InvalidOperationException (
169+ StringResources . TypeAlreadyRegistered ( producerToRegister . ServiceType ) ) ;
170+ }
171+ }
160172
161- throw eitherOneRegistrationIsConditional
162- ? GetAnOverlappingGenericRegistrationExistsException (
163- new ClosedToInstanceProducerProvider ( producerToRegister ) ,
164- overlappingProvider )
165- : new InvalidOperationException (
166- StringResources . TypeAlreadyRegistered ( producerToRegister . ServiceType ) ) ;
173+ private IProducerProvider ? GetFirstOverlappingProvider ( InstanceProducer producerToRegister )
174+ {
175+ foreach ( var provider in this . providers )
176+ {
177+ if ( provider . OverlapsWith ( producerToRegister ) )
178+ {
179+ return provider ;
167180 }
168181 }
182+
183+ return null ;
169184 }
170185
171186 private void ThrowWhenConditionalIsRegisteredInOverridingMode ( InstanceProducer producer )
172187 {
173- if ( producer . IsConditional
174- && this . container . Options . AllowOverridingRegistrations
175- && this . providers . Any ( ) )
188+ if ( ! this . IsEmpty && producer . IsConditional && this . AllowOverridingRegistrations )
176189 {
177190 throw new NotSupportedException (
178191 StringResources . MakingConditionalRegistrationsInOverridingModeIsNotSupported ( ) ) ;
@@ -182,8 +195,8 @@ private void ThrowWhenConditionalIsRegisteredInOverridingMode(InstanceProducer p
182195 private void ThrowWhenConditionalIsRegisteredInOverridingMode (
183196 OpenGenericToInstanceProducerProvider provider )
184197 {
185- if ( this . providers . Count > 0
186- && this . container . Options . AllowOverridingRegistrations
198+ if ( ! this . IsEmpty
199+ && this . AllowOverridingRegistrations
187200 && ! provider . GetAppliesToAllClosedServiceTypes ( ) )
188201 {
189202 if ( provider . Predicate != null )
@@ -203,37 +216,54 @@ private void ThrowWhenProviderToRegisterOverlapsWithExistingProvider(
203216 OpenGenericToInstanceProducerProvider providerToRegister )
204217 {
205218 bool providerToRegisterIsSuperset =
206- this . providers . Count > 0 && providerToRegister . GetAppliesToAllClosedServiceTypes ( ) ;
219+ ! this . IsEmpty && providerToRegister . GetAppliesToAllClosedServiceTypes ( ) ;
207220
208221 // A provider with AppliesToAllClosedServiceTypes true will always have an ImplementationType,
209222 // because the property will always be false for providers with a factory.
210223 Type providerImplementationType = providerToRegister . ImplementationType ! ;
211224
212- bool isReplacement = this . container . Options . AllowOverridingRegistrations
225+ bool isReplacement = this . AllowOverridingRegistrations
213226 && providerToRegister . GetAppliesToAllClosedServiceTypes ( ) ;
214227
215228 // A provider is a superset of the providerToRegister when it can be applied to ALL generic
216229 // types that the providerToRegister can be applied to as well.
217- var supersetProviders = this . GetSupersetProvidersFor ( providerImplementationType ) ;
230+ var supersetProvider = this . GetFirstOrDefaultSupersetProvidersFor ( providerImplementationType ) ;
218231
219- bool overlaps = providerToRegisterIsSuperset || supersetProviders . Any ( ) ;
232+ bool overlaps = providerToRegisterIsSuperset || supersetProvider != null ;
220233
221234 if ( ! isReplacement && overlaps )
222235 {
223- var overlappingProvider = supersetProviders . FirstOrDefault ( ) ?? this . providers [ 0 ] ;
236+ var overlappingProvider = supersetProvider ?? this . providers [ 0 ] ;
224237
225238 throw GetAnOverlappingGenericRegistrationExistsException (
226239 providerToRegister ,
227240 overlappingProvider ) ;
228241 }
229242 }
230243
231- private IEnumerable < IProducerProvider > GetSupersetProvidersFor ( Type implementationType ) =>
232- from provider in this . providers
233- where implementationType != null
234- where provider . ImplementationType != null
235- where provider . ImplementationType == implementationType || provider . GetAppliesToAllClosedServiceTypes ( )
236- select provider ;
244+ private IProducerProvider ? GetFirstOrDefaultSupersetProvidersFor ( Type implementationType )
245+ {
246+ if ( implementationType is null || this . IsEmpty )
247+ {
248+ return null ;
249+ }
250+ else
251+ {
252+ foreach ( var provider in this . providers )
253+ {
254+ if ( provider . ImplementationType != null )
255+ {
256+ if ( provider . ImplementationType == implementationType
257+ || provider . GetAppliesToAllClosedServiceTypes ( ) )
258+ {
259+ return provider ;
260+ }
261+ }
262+ }
263+
264+ return null ;
265+ }
266+ }
237267
238268 private static InvalidOperationException GetAnOverlappingGenericRegistrationExistsException (
239269 IProducerProvider providerToRegister , IProducerProvider overlappingProvider ) => new (
0 commit comments