180 lines
6.1 KiB
C#

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>(T registrationBuilder) where T : RegistrationBuilder;
void RegisterBuildCallback(Action<IObjectResolver> 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<RegistrationBuilder> registrationBuilders = new List<RegistrationBuilder>();
Action<IObjectResolver> buildCallback;
DiagnosticsCollector diagnostics;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T Register<T>(T registrationBuilder) where T : RegistrationBuilder
{
registrationBuilders.Add(registrationBuilder);
Diagnostics?.TraceRegister(new RegisterInfo(registrationBuilder));
return registrationBuilder;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RegisterBuildCallback(Action<IObjectResolver> 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);
}
}
}