Files
2026-09-21 12:15:57 +03:00

160 lines
4.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Reflex.Exceptions;
using Reflex.Extensions;
using Reflex.Generics;
using Reflex.Injectors;
using Reflex.Logging;
using Reflex.Resolvers;
namespace Reflex.Core
{
public sealed class Container : IDisposable
{
public static Container RootContainer { get; internal set; }
public string Name { get; }
public Container Parent { get; }
internal List<Container> Children { get; } = new();
internal Dictionary<Type, List<IResolver>> ResolversByContract { get; }
internal DisposableCollection Disposables { get; }
#if UNITY_EDITOR
internal static readonly List<Container> RootContainers = new();
#endif
internal Container(string name, Container parent, Dictionary<Type, List<IResolver>> resolversByContract, DisposableCollection disposables)
{
Diagnosis.RegisterBuildCallSite(this);
Name = name;
Parent = parent;
Parent?.Children.Add(this);
ResolversByContract = resolversByContract;
Disposables = disposables;
OverrideSelfInjection();
#if UNITY_EDITOR
if (parent == null)
{
RootContainers.Add(this);
}
#endif
}
public bool HasBinding<T>()
{
return HasBinding(typeof(T));
}
public bool HasBinding(Type type)
{
return ResolversByContract.ContainsKey(type);
}
public void Dispose()
{
foreach (var child in Children.Reversed())
{
child.Dispose();
}
Parent?.Children.Remove(this);
ResolversByContract.Clear();
Disposables.Dispose();
ReflexLogger.Log($"Container {Name} disposed", LogLevel.Info);
}
public Container Scope(Action<ContainerBuilder> extend = null)
{
var builder = new ContainerBuilder().SetParent(this);
extend?.Invoke(builder);
var scoped = builder.Build();
return scoped;
}
public T Construct<T>()
{
return (T)Construct(typeof(T));
}
public object Construct(Type concrete)
{
var instance = ConstructorInjector.Construct(concrete, this);
AttributeInjector.Inject(instance, this);
return instance;
}
public object Resolve(Type type)
{
if (type.IsEnumerable(out var elementType))
{
return All(elementType).CastDynamic(elementType);
}
var resolvers = GetResolvers(type);
var lastResolver = resolvers.Last();
var resolved = lastResolver.Resolve(this);
return resolved;
}
public TContract Resolve<TContract>()
{
return (TContract)Resolve(typeof(TContract));
}
public object Single(Type type)
{
return GetResolvers(type).Single().Resolve(this);
}
public TContract Single<TContract>()
{
return (TContract)Single(typeof(TContract));
}
public bool TryGetResolver(Type contract, out IResolver result)
{
if (ResolversByContract.TryGetValue(contract, out var resolvers))
{
result = resolvers.Single();
return true;
}
result = null;
return false;
}
public bool TryGetResolver<TContract>(out IResolver result)
{
return TryGetResolver(typeof(TContract), out result);
}
public IEnumerable<object> All(Type contract)
{
return ResolversByContract.TryGetValue(contract, out var resolvers)
? resolvers.Select(resolver => resolver.Resolve(this)).ToArray()
: Enumerable.Empty<object>();
}
public IEnumerable<TContract> All<TContract>()
{
return ResolversByContract.TryGetValue(typeof(TContract), out var resolvers)
? resolvers.Select(resolver => (TContract) resolver.Resolve(this)).ToArray()
: Enumerable.Empty<TContract>();
}
private IEnumerable<IResolver> GetResolvers(Type contract)
{
if (ResolversByContract.TryGetValue(contract, out var resolvers))
{
return resolvers;
}
throw new UnknownContractException(contract);
}
private void OverrideSelfInjection()
{
ResolversByContract[typeof(Container)] = new List<IResolver> { new SingletonValueResolver(this) };
}
}
}