11// Licensed to the .NET Foundation under one or more agreements.
22// The .NET Foundation licenses this file to you under the MIT license.
33
4+ using System . Diagnostics ;
45using System . Diagnostics . CodeAnalysis ;
56using System . Globalization ;
6- using System . Linq ;
77using System . Reflection ;
88using Microsoft . Extensions . DependencyInjection ;
99
@@ -93,8 +93,8 @@ private static bool ResolveParameterPolicyTypeAndArgument(
9393 [ UnconditionalSuppressMessage ( "ReflectionAnalysis" , "IL2070" , Justification = "We ensure the constructor is preserved when the constraint map is added." ) ]
9494 private static IParameterPolicy CreateParameterPolicy ( IServiceProvider ? serviceProvider , Type parameterPolicyType , string ? argumentString )
9595 {
96- ConstructorInfo ? activationConstructor = null ;
97- object ? [ ] ? parameters = null ;
96+ ConstructorInfo ? activationConstructor ;
97+ object ? [ ] ? parameters ;
9898 var constructors = parameterPolicyType . GetConstructors ( ) ;
9999
100100 // If there is only one constructor and it has a single parameter, pass the argument string directly
@@ -113,30 +113,24 @@ private static IParameterPolicy CreateParameterPolicy(IServiceProvider? serviceP
113113 // arguments that can be resolved from DI
114114 //
115115 // For example, ctor(string, IService) will beat ctor(string)
116- var matchingConstructors = constructors
117- . Where ( ci => GetNonConvertableParameterTypeCount ( serviceProvider , ci . GetParameters ( ) ) == arguments . Length )
118- . OrderByDescending ( ci => ci . GetParameters ( ) . Length )
119- . ToArray ( ) ;
116+ var matchingConstructors = GetMatchingConstructors ( constructors , serviceProvider , arguments . Length ) ;
120117
121- if ( matchingConstructors . Length == 0 )
118+ if ( matchingConstructors . Count == 0 )
122119 {
123120 throw new RouteCreationException (
124121 Resources . FormatDefaultInlineConstraintResolver_CouldNotFindCtor (
125122 parameterPolicyType . Name , arguments . Length ) ) ;
126123 }
127124 else
128125 {
129- // When there are multiple matching constructors, choose the one with the most service arguments
130- if ( matchingConstructors . Length == 1
131- || matchingConstructors [ 0 ] . GetParameters ( ) . Length > matchingConstructors [ 1 ] . GetParameters ( ) . Length )
126+ if ( matchingConstructors . Count == 1 )
132127 {
133128 activationConstructor = matchingConstructors [ 0 ] ;
134129 }
135130 else
136131 {
137- throw new RouteCreationException (
138- Resources . FormatDefaultInlineConstraintResolver_AmbiguousCtors (
139- parameterPolicyType . Name , matchingConstructors [ 0 ] . GetParameters ( ) . Length ) ) ;
132+ // When there are multiple matching constructors, choose the one with the most service arguments
133+ activationConstructor = GetLongestConstructor ( matchingConstructors , parameterPolicyType ) ;
140134 }
141135
142136 parameters = ConvertArguments ( serviceProvider , activationConstructor . GetParameters ( ) , arguments ) ;
@@ -146,6 +140,52 @@ private static IParameterPolicy CreateParameterPolicy(IServiceProvider? serviceP
146140 return ( IParameterPolicy ) activationConstructor . Invoke ( parameters ) ;
147141 }
148142
143+ private static List < ConstructorInfo > GetMatchingConstructors ( ConstructorInfo [ ] constructors , IServiceProvider ? serviceProvider , int argumentsLength )
144+ {
145+ var result = new List < ConstructorInfo > ( ) ;
146+ foreach ( var constructor in constructors )
147+ {
148+ if ( GetNonConvertableParameterTypeCount ( serviceProvider , constructor . GetParameters ( ) ) == argumentsLength )
149+ {
150+ result . Add ( constructor ) ;
151+ }
152+ }
153+ return result ;
154+ }
155+
156+ private static ConstructorInfo GetLongestConstructor ( List < ConstructorInfo > constructors , Type parameterPolicyType )
157+ {
158+ Debug . Assert ( constructors . Count > 0 ) ;
159+
160+ var longestLength = - 1 ;
161+ ConstructorInfo ? longest = null ;
162+ var multipleBestLengthFound = false ;
163+
164+ foreach ( var constructor in constructors )
165+ {
166+ var length = constructor . GetParameters ( ) . Length ;
167+ if ( length > longestLength )
168+ {
169+ multipleBestLengthFound = false ;
170+ longestLength = length ;
171+ longest = constructor ;
172+ }
173+ else if ( longestLength == length )
174+ {
175+ multipleBestLengthFound = true ;
176+ }
177+ }
178+
179+ if ( multipleBestLengthFound )
180+ {
181+ throw new RouteCreationException (
182+ Resources . FormatDefaultInlineConstraintResolver_AmbiguousCtors (
183+ parameterPolicyType . Name , longestLength ) ) ;
184+ }
185+
186+ return longest ! ;
187+ }
188+
149189 private static int GetNonConvertableParameterTypeCount ( IServiceProvider ? serviceProvider , ParameterInfo [ ] parameters )
150190 {
151191 if ( serviceProvider == null )
0 commit comments