using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using VContainer.Diagnostics; using VContainer.Internal; #if VCONTAINER_PARALLEL_CONTAINER_BUILD using System.Threading.Tasks; #endif namespace VContainer { public interface IContainerBuilder { object ApplicationOrigin { get; set; } DiagnosticsCollector Diagnostics { get; set; } int Count { get; } RegistrationBuilder this[int index] { get; set; } T Register(T registrationBuilder) where T : RegistrationBuilder; void RegisterBuildCallback(Action container); bool Exists(Type type, bool includeInterfaceTypes = false, bool findParentScopes = false); } public sealed class ScopedContainerBuilder : ContainerBuilder { readonly IObjectResolver root; readonly IScopedObjectResolver parent; internal ScopedContainerBuilder(IObjectResolver root, IScopedObjectResolver parent) { this.root = root; this.parent = parent; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public IScopedObjectResolver BuildScope() { var registry = BuildRegistry(); var container = new ScopedContainer(registry, root, parent, ApplicationOrigin); container.Diagnostics = Diagnostics; EmitCallbacks(container); return container; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override IObjectResolver Build() => BuildScope(); public override bool Exists(Type type, bool includeInterfaceTypes = false, bool findParentScopes = false) { if (base.Exists(type, includeInterfaceTypes, findParentScopes)) { return true; } if (findParentScopes) { var next = parent; while (next != null) { if (next.TryGetRegistration(type, out var registration)) { if (includeInterfaceTypes || registration.ImplementationType == type) { return true; } } next = next.Parent; } } return false; } } public class ContainerBuilder : IContainerBuilder { public object ApplicationOrigin { get; set; } public int Count => registrationBuilders.Count; public RegistrationBuilder this[int index] { get => registrationBuilders[index]; set => registrationBuilders[index] = value; } public DiagnosticsCollector Diagnostics { get => diagnostics; set { diagnostics = value; diagnostics?.Clear(); } } readonly List registrationBuilders = new List(); Action buildCallback; DiagnosticsCollector diagnostics; [MethodImpl(MethodImplOptions.AggressiveInlining)] public T Register(T registrationBuilder) where T : RegistrationBuilder { registrationBuilders.Add(registrationBuilder); Diagnostics?.TraceRegister(new RegisterInfo(registrationBuilder)); return registrationBuilder; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RegisterBuildCallback(Action callback) { buildCallback += callback; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual bool Exists(Type type, bool includeInterfaceTypes = false, bool findParentScopes = false) { foreach (var registrationBuilder in registrationBuilders) { if (registrationBuilder.ImplementationType == type || includeInterfaceTypes && registrationBuilder.InterfaceTypes?.Contains(type) == true) { return true; } } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual IObjectResolver Build() { var registry = BuildRegistry(); var container = new Container(registry, ApplicationOrigin); container.Diagnostics = Diagnostics; EmitCallbacks(container); return container; } [MethodImpl(MethodImplOptions.AggressiveInlining)] protected Registry BuildRegistry() { var registrations = new Registration[registrationBuilders.Count + 1]; #if VCONTAINER_PARALLEL_CONTAINER_BUILD Parallel.For(0, registrationBuilders.Count, i => { var registrationBuilder = registrationBuilders[i]; var registration = registrationBuilder.Build(); Diagnostics?.TraceBuild(registrationBuilder, registration); registrations[i] = registration; }); #else for (var i = 0; i < registrationBuilders.Count; i++) { var registrationBuilder = registrationBuilders[i]; var registration = registrationBuilder.Build(); Diagnostics?.TraceBuild(registrationBuilder, registration); registrations[i] = registration; } #endif registrations[registrations.Length - 1] = new Registration( typeof(IObjectResolver), Lifetime.Transient, null, ContainerInstanceProvider.Default); var registry = Registry.Build(registrations); TypeAnalyzer.CheckCircularDependency(registrations, registry); return registry; } [MethodImpl(MethodImplOptions.AggressiveInlining)] protected void EmitCallbacks(IObjectResolver container) { buildCallback?.Invoke(container); Diagnostics?.NotifyContainerBuilt(container); } } }