using System; using System.Collections.Generic; using System.Reflection; namespace Spectre.Console.Cli.Internal { internal abstract class ComponentActivator { public abstract object Activate(DefaultTypeResolver container); public abstract ComponentActivator CreateCopy(); } internal class CachingActivator : ComponentActivator { private readonly ComponentActivator _activator; private object? _result; public CachingActivator(ComponentActivator activator) { _activator = activator ?? throw new ArgumentNullException(nameof(activator)); _result = null; } public override object Activate(DefaultTypeResolver container) { return _result ??= _activator.Activate(container); } public override ComponentActivator CreateCopy() { return new CachingActivator(_activator.CreateCopy()); } } internal sealed class InstanceActivator : ComponentActivator { private readonly object _instance; public InstanceActivator(object instance) { _instance = instance; } public override object Activate(DefaultTypeResolver container) { return _instance; } public override ComponentActivator CreateCopy() { return new InstanceActivator(_instance); } } internal sealed class ReflectionActivator : ComponentActivator { private readonly Type _type; private readonly ConstructorInfo _constructor; private readonly List _parameters; public ReflectionActivator(Type type) { _type = type; _constructor = GetGreediestConstructor(type); _parameters = new List(); foreach (var parameter in _constructor.GetParameters()) { _parameters.Add(parameter); } } public override object Activate(DefaultTypeResolver container) { var parameters = new object?[_parameters.Count]; for (var i = 0; i < _parameters.Count; i++) { var parameter = _parameters[i]; if (parameter.ParameterType == typeof(DefaultTypeResolver)) { parameters[i] = container; } else { var resolved = container.Resolve(parameter.ParameterType); if (resolved == null) { if (!parameter.IsOptional) { throw new InvalidOperationException($"Could not find registration for '{parameter.ParameterType.FullName}'."); } parameters[i] = null; } else { parameters[i] = resolved; } } } return _constructor.Invoke(parameters); } public override ComponentActivator CreateCopy() { return new ReflectionActivator(_type); } private static ConstructorInfo GetGreediestConstructor(Type type) { ConstructorInfo? current = null; var count = -1; foreach (var constructor in type.GetTypeInfo().GetConstructors()) { var parameters = constructor.GetParameters(); if (parameters.Length > count) { count = parameters.Length; current = constructor; } } if (current == null) { throw new InvalidOperationException($"Could not find a constructor for '{type.FullName}'."); } return current; } } }