115 lines
4.3 KiB
C#

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<IInjectParameter> parameters)
{
InjectFields(instance, resolver, parameters);
InjectProperties(instance, resolver, parameters);
InjectMethods(instance, resolver, parameters);
}
public object CreateInstance(IObjectResolver resolver, IReadOnlyList<IInjectParameter> parameters)
{
var parameterInfos = injectTypeInfo.InjectConstructor.ParameterInfos;
var parameterValues = CappedArrayPool<object>.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<object>.Shared8Limit.Return(parameterValues);
}
}
void InjectFields(object obj, IObjectResolver resolver, IReadOnlyList<IInjectParameter> 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<IInjectParameter> 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<IInjectParameter> parameters)
{
if (injectTypeInfo.InjectMethods == null)
return;
foreach (var method in injectTypeInfo.InjectMethods)
{
var parameterInfos = method.ParameterInfos;
var parameterValues = CappedArrayPool<object>.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<object>.Shared8Limit.Return(parameterValues);
}
}
}
}
}