private InstanceProducer BuildInstanceProducerForMetadataList(Type enumerableOfProducersType) { Type metadataType = enumerableOfProducersType.GetGenericArguments()[0]; Type serviceType = metadataType.GetGenericArguments()[0]; var collection = this.container.GetAllInstances(serviceType) as IContainerControlledCollection; if (collection is null) { // This exception might not be expressive enough. If GetAllInstances succeeds, but the // returned type is not an IContainerControlledCollection, it likely means the collection is // container uncontrolled. this.container.ThrowMissingInstanceProducerException(serviceType); } IContainerControlledCollection metadataCollection = ControlledCollectionHelper.CreateContainerControlledCollection(metadataType, this.container); metadataCollection.AppendAll( from producer in collection !.GetProducers() let metadata = CreateMetadata(metadataType, producer) let reg = Lifestyle.Singleton.CreateRegistration(metadataType, metadata, this.container) select ContainerControlledItem.CreateFromRegistration(reg)); return(new InstanceProducer( serviceType: enumerableOfProducersType, registration: metadataCollection.CreateRegistration(enumerableOfProducersType, this.container))); }
private InstanceProducer BuildEmptyCollectionInstanceProducerForEnumerable(Type enumerableType) { Type elementType = enumerableType.GetGenericArguments()[0]; var collection = ControlledCollectionHelper.CreateContainerControlledCollection(elementType, this); var registration = new ExpressionRegistration(Expression.Constant(collection, enumerableType), this); // Producers for ExpressionRegistration are normally ignored as external producer, but in this // case the empty collection producer should pop up in the list of GetCurrentRegistrations(). return(new InstanceProducer(enumerableType, registration, registerExternalProducer: true)); }
// Implements #553 private TImplementation CreateInstance(Func <TImplementation> instanceCreator) { var isCurrentThread = new ThreadLocal <bool> { Value = true }; // Create a listener that can spot when an injected stream is iterated during construction. Action <ServiceCreatedListenerArgs> listener = args => { // Only handle when an inner registration hasn't handled this yet. if (!args.Handled) { // Only handle when the call originates from the same thread, as calls from different // threads mean the listener is not triggered from this specific instanceCreator. if (isCurrentThread.Value) { args.Handled = true; var matchingRelationship = this.FindMatchingCollectionRelationship(args.Producer); var additionalInformation = StringResources.CollectionUsedDuringConstruction( typeof(TImplementation), args.Producer, matchingRelationship); // At this point, an injected ContainerControlledCollection<T> has notified the // listener about the creation of one of its elements. This has happened during // the construction of this (Singleton) instance, which might cause Lifestyle // Mismatches. That's why this is added as a known relationship. This way // diagnostics can verify the relationship. this.AddRelationship( new KnownRelationship( implementationType: typeof(TImplementation), lifestyle: this.Lifestyle, consumer: matchingRelationship?.Consumer ?? InjectionConsumerInfo.Root, dependency: args.Producer, additionalInformation: additionalInformation)); } } }; try { ControlledCollectionHelper.AddServiceCreatedListener(listener); return(instanceCreator()); } finally { ControlledCollectionHelper.RemoveServiceCreatedListener(listener); isCurrentThread.Dispose(); } }
private void TryToApplyDecoratorOnContainerUncontrolledCollections(ExpressionBuiltEventArgs e) { if (!IsCollectionType(e.RegisteredServiceType) || ControlledCollectionHelper.IsContainerControlledCollectionExpression(e.Expression)) { // NOTE: Decorators on controlled collections will be applied by the normal mechanism. return; } var serviceType = e.RegisteredServiceType.GetGenericArguments()[0]; if (this.MustDecorate(serviceType, out Type? decoratorType)) { this.ApplyDecoratorOnContainerUncontrolledCollection(e, decoratorType); } }
// Implements #553 Allows detection of Lifestyle Mismatches when iterated inside constructor. private object Execute(Func<object> instanceCreator) { var isCurrentThread = new ThreadLocal<bool> { Value = true }; // Create a listener that can spot when an injected stream is iterated during construction. var listener = this.CreateCollectionUsedDuringConstructionListener(isCurrentThread); try { ControlledCollectionHelper.AddServiceCreatedListener(listener); return instanceCreator(); } finally { ControlledCollectionHelper.RemoveServiceCreatedListener(listener); isCurrentThread.Dispose(); } }