Skip to content

Commit

Permalink
Fix "Best Match" ctor selection
Browse files Browse the repository at this point in the history
It was not taking Keyed imports into account (fixes 4 failures in MS DI specifications).
Added PolySharp dependency in .net 4.6.2 to be able to use new C# features.
  • Loading branch information
jods4 committed Jan 5, 2024
1 parent d3b277b commit be118fc
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 34 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Grace.DependencyInjection.Attributes.Interfaces;

namespace Grace.DependencyInjection.Impl.Expressions
{
Expand All @@ -16,30 +17,25 @@ public class BestMatchConstructorExpressionCreator : ConstructorExpressionCreato
/// <param name="configuration"></param>
/// <param name="request"></param>
/// <param name="constructors"></param>
protected override ConstructorInfo PickConstructor(IInjectionScope injectionScope, TypeActivationConfiguration configuration,
IActivationExpressionRequest request, ConstructorInfo[] constructors)
protected override ConstructorInfo PickConstructor(
IInjectionScope injectionScope,
TypeActivationConfiguration configuration,
IActivationExpressionRequest request,
ConstructorInfo[] constructors)
{
ConstructorInfo returnConstructor = null;
var matchInfos = new List<MatchInfo>();

foreach (var constructor in constructors)
foreach (var constructor in constructors.OrderByDescending(c => c.GetParameters().Length))
{
var matchInfo = new MatchInfo { ConstructorInfo = constructor };

foreach (var parameter in constructor.GetParameters())
{
object key = null;

if (injectionScope.ScopeConfiguration.Behaviors.KeyedTypeSelector(parameter.ParameterType))
{
key = parameter.Name;
}

if (parameter.IsOptional ||
parameter.ParameterType.IsGenericParameter ||
CanGetValueFromInfo(configuration, parameter) ||
CanGetValueFromKnownValues(request, parameter) ||
injectionScope.CanLocate(parameter.ParameterType, null, key))
injectionScope.CanLocate(parameter.ParameterType, null, GetKey(injectionScope, parameter)))
{
matchInfo.Matched++;
}
Expand All @@ -51,23 +47,39 @@ protected override ConstructorInfo PickConstructor(IInjectionScope injectionScop

if (matchInfo.Missing == 0)
{
returnConstructor = constructor;
break;
return constructor;
}

matchInfos.Add(matchInfo);
}

if (returnConstructor == null)
{
var comparer = Comparer<int>.Default;
#if NET6_0_OR_GREATER

matchInfos.Sort((x, y) => comparer.Compare(x.Matched - x.Missing, y.Matched - y.Missing));
return matchInfos.MaxBy(x => x.Matched - x.Missing).ConstructorInfo;

#else

var comparer = Comparer<int>.Default;
matchInfos.Sort((x, y) => comparer.Compare(x.Matched - x.Missing, y.Matched - y.Missing));
return matchInfos.Last().ConstructorInfo;

#endif
}

returnConstructor = matchInfos.Last().ConstructorInfo;
private object GetKey(IInjectionScope scope, ParameterInfo parameter)
{
var importInfo = ImportAttributeInfo.For(parameter, parameter.ParameterType, parameter.Name);
if (importInfo != null)
{
return importInfo.ImportKey;
}

return returnConstructor;

if (scope.ScopeConfiguration.Behaviors.KeyedTypeSelector(parameter.ParameterType))
{
return parameter.Name;
}

return null;
}

private bool CanGetValueFromKnownValues(IActivationExpressionRequest request, ParameterInfo parameter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,19 +298,18 @@ protected virtual ConstructorInfo PickConstructor(IInjectionScope requestingScop
return configuration.SelectedConstructor;
}

var constructors = configuration.ActivationType.GetTypeInfo().DeclaredConstructors.Where(c => c.IsPublic && !c.IsStatic).OrderByDescending(c => c.GetParameters().Length).ToArray();

if (constructors.Length == 0)
{
throw new Exception("Could not find public constructor on type " + configuration.ActivationType.FullName);
}

if (constructors.Length == 1)
var constructors = configuration
.ActivationType.GetTypeInfo()
.DeclaredConstructors
.Where(c => c.IsPublic && !c.IsStatic)
.ToArray();

return constructors switch
{
return constructors[0];
}

return PickConstructor(requestingScope, configuration, request, constructors);
[] => throw new Exception("Could not find public constructor on type " + configuration.ActivationType.FullName),
[var ctor] => ctor,
_ => PickConstructor(requestingScope, configuration, request, constructors),
};
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,11 @@ private Tuple<ParameterExpression, Expression> CreateCanLocateStatement(Paramete
protected override ConstructorInfo PickConstructor(IInjectionScope injectionScope, TypeActivationConfiguration configuration,
IActivationExpressionRequest request, ConstructorInfo[] constructors)
{
return constructors.OrderByDescending(c => c.GetParameters().Length).First();
#if NET6_0_OR_GREATER
return constructors.MinBy(c => c.GetParameters().Length);
#else
return constructors.OrderBy(c => c.GetParameters().Length).First();
#endif
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ public class LeastParametersConstructorExpressionCreator : ConstructorExpression
protected override ConstructorInfo PickConstructor(IInjectionScope injectionScope, TypeActivationConfiguration configuration,
IActivationExpressionRequest request, ConstructorInfo[] constructors)
{
#if NET6_0_OR_GREATER
return constructors.MinBy(c => c.GetParameters().Length);
#else
return constructors.OrderBy(c => c.GetParameters().Length).First();
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ public class MostParametersConstructorExpressionCreator : ConstructorExpressionC
protected override ConstructorInfo PickConstructor(IInjectionScope injectionScope, TypeActivationConfiguration configuration,
IActivationExpressionRequest request, ConstructorInfo[] constructors)
{
#if NET6_0_OR_GREATER
return constructors.MaxBy(c => c.GetParameters().Length);
#else
return constructors.OrderByDescending(c => c.GetParameters().Length).First();
#endif
}
}
}
1 change: 1 addition & 0 deletions src/Grace/Grace.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageReference Include="System.ComponentModel.Composition" Version="7.0.0" />
<PackageReference Include="PolySharp" Version="1.14.1" />
</ItemGroup>

</Project>

0 comments on commit be118fc

Please sign in to comment.