using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace VContainer.Internal { sealed class ReflectionInjector : IInjector { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ReflectionInjector Build(Type type) { var injectTypeInfo = TypeAnalyzer.AnalyzeWithCache(type); return new ReflectionInjector(injectTypeInfo); } readonly InjectTypeInfo injectTypeInfo; ReflectionInjector(InjectTypeInfo injectTypeInfo) { this.injectTypeInfo = injectTypeInfo; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Inject(object instance, IObjectResolver resolver, IReadOnlyList parameters) { InjectFields(instance, resolver, parameters); InjectProperties(instance, resolver, parameters); InjectMethods(instance, resolver, parameters); } public object CreateInstance(IObjectResolver resolver, IReadOnlyList parameters) { var parameterInfos = injectTypeInfo.InjectConstructor.ParameterInfos; var parameterValues = CappedArrayPool.Shared8Limit.Rent(parameterInfos.Length); try { for (var i = 0; i < parameterInfos.Length; i++) { var parameterInfo = parameterInfos[i]; parameterValues[i] = resolver.ResolveOrParameter( parameterInfo.ParameterType, parameterInfo.Name, parameters); } var instance = injectTypeInfo.InjectConstructor.ConstructorInfo.Invoke(parameterValues); Inject(instance, resolver, parameters); return instance; } catch (VContainerException ex) { throw new VContainerException(ex.InvalidType, $"Failed to resolve {injectTypeInfo.Type} : {ex.Message}"); } finally { CappedArrayPool.Shared8Limit.Return(parameterValues); } } void InjectFields(object obj, IObjectResolver resolver, IReadOnlyList parameters) { if (injectTypeInfo.InjectFields == null) return; foreach (var x in injectTypeInfo.InjectFields) { var fieldValue = resolver.ResolveOrParameter(x.FieldType, x.Name, parameters); x.SetValue(obj, fieldValue); } } void InjectProperties(object obj, IObjectResolver resolver, IReadOnlyList parameters) { if (injectTypeInfo.InjectProperties == null) return; foreach (var x in injectTypeInfo.InjectProperties) { var propValue = resolver.ResolveOrParameter(x.PropertyType, x.Name, parameters); x.SetValue(obj, propValue); } } void InjectMethods(object obj, IObjectResolver resolver, IReadOnlyList parameters) { if (injectTypeInfo.InjectMethods == null) return; foreach (var method in injectTypeInfo.InjectMethods) { var parameterInfos = method.ParameterInfos; var parameterValues = CappedArrayPool.Shared8Limit.Rent(parameterInfos.Length); try { for (var i = 0; i < parameterInfos.Length; i++) { var parameterInfo = parameterInfos[i]; parameterValues[i] = resolver.ResolveOrParameter( parameterInfo.ParameterType, parameterInfo.Name, parameters); } method.MethodInfo.Invoke(obj, parameterValues); } catch (VContainerException ex) { throw new VContainerException(ex.InvalidType, $"Failed to resolve {injectTypeInfo.Type} : {ex.Message}"); } finally { CappedArrayPool.Shared8Limit.Return(parameterValues); } } } } }