ActivatorUtilities.CreateInstance: allocation optimization

\n\nCommit migrated from 689a832ced
This commit is contained in:
Yves Marx 2019-06-05 08:19:46 +02:00
parent 73e95c56c1
commit f402cc566a
1 changed files with 25 additions and 26 deletions

View File

@ -43,43 +43,45 @@ namespace Microsoft.Extensions.Internal
int bestLength = -1; int bestLength = -1;
var seenPreferred = false; var seenPreferred = false;
ConstructorMatcher bestMatcher = null; ConstructorMatcher bestMatcher = default;
if (!instanceType.GetTypeInfo().IsAbstract) if (!instanceType.GetTypeInfo().IsAbstract)
{ {
foreach (var constructor in instanceType foreach (var constructor in instanceType
.GetTypeInfo() .GetTypeInfo()
.DeclaredConstructors .DeclaredConstructors)
.Where(c => !c.IsStatic && c.IsPublic))
{ {
var matcher = new ConstructorMatcher(constructor); if (!constructor.IsStatic && constructor.IsPublic)
var isPreferred = constructor.IsDefined(typeof(ActivatorUtilitiesConstructorAttribute), false);
var length = matcher.Match(parameters);
if (isPreferred)
{ {
if (seenPreferred) var matcher = new ConstructorMatcher(constructor);
var isPreferred = constructor.IsDefined(typeof(ActivatorUtilitiesConstructorAttribute), false);
var length = matcher.Match(parameters);
if (isPreferred)
{ {
ThrowMultipleCtorsMarkedWithAttributeException(); if (seenPreferred)
{
ThrowMultipleCtorsMarkedWithAttributeException();
}
if (length == -1)
{
ThrowMarkedCtorDoesNotTakeAllProvidedArguments();
}
} }
if (length == -1) if (isPreferred || bestLength < length)
{ {
ThrowMarkedCtorDoesNotTakeAllProvidedArguments(); bestLength = length;
bestMatcher = matcher;
} }
}
if (isPreferred || bestLength < length) seenPreferred |= isPreferred;
{
bestLength = length;
bestMatcher = matcher;
} }
seenPreferred |= isPreferred;
} }
} }
if (bestMatcher == null) if (bestLength == -1)
{ {
var message = $"A suitable constructor for type '{instanceType}' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor."; var message = $"A suitable constructor for type '{instanceType}' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.";
throw new InvalidOperationException(message); throw new InvalidOperationException(message);
@ -327,18 +329,16 @@ namespace Microsoft.Extensions.Internal
return true; return true;
} }
private class ConstructorMatcher private struct ConstructorMatcher
{ {
private readonly ConstructorInfo _constructor; private readonly ConstructorInfo _constructor;
private readonly ParameterInfo[] _parameters; private readonly ParameterInfo[] _parameters;
private readonly object[] _parameterValues; private readonly object[] _parameterValues;
private readonly bool[] _parameterValuesSet;
public ConstructorMatcher(ConstructorInfo constructor) public ConstructorMatcher(ConstructorInfo constructor)
{ {
_constructor = constructor; _constructor = constructor;
_parameters = _constructor.GetParameters(); _parameters = _constructor.GetParameters();
_parameterValuesSet = new bool[_parameters.Length];
_parameterValues = new object[_parameters.Length]; _parameterValues = new object[_parameters.Length];
} }
@ -353,11 +353,10 @@ namespace Microsoft.Extensions.Internal
for (var applyIndex = applyIndexStart; givenMatched == false && applyIndex != _parameters.Length; ++applyIndex) for (var applyIndex = applyIndexStart; givenMatched == false && applyIndex != _parameters.Length; ++applyIndex)
{ {
if (_parameterValuesSet[applyIndex] == false && if (_parameterValues[applyIndex] == null &&
_parameters[applyIndex].ParameterType.GetTypeInfo().IsAssignableFrom(givenType)) _parameters[applyIndex].ParameterType.GetTypeInfo().IsAssignableFrom(givenType))
{ {
givenMatched = true; givenMatched = true;
_parameterValuesSet[applyIndex] = true;
_parameterValues[applyIndex] = givenParameters[givenIndex]; _parameterValues[applyIndex] = givenParameters[givenIndex];
if (applyIndexStart == applyIndex) if (applyIndexStart == applyIndex)
{ {
@ -382,7 +381,7 @@ namespace Microsoft.Extensions.Internal
{ {
for (var index = 0; index != _parameters.Length; index++) for (var index = 0; index != _parameters.Length; index++)
{ {
if (_parameterValuesSet[index] == false) if (_parameterValues[index] == null)
{ {
var value = provider.GetService(_parameters[index].ParameterType); var value = provider.GetService(_parameters[index].ParameterType);
if (value == null) if (value == null)