@@ -17,19 +17,19 @@ public MethodFinder(ParsingConfig parsingConfig)
1717 _parsingConfig = parsingConfig ;
1818 }
1919
20- public bool ContainsMethod ( Type type , string methodName , bool staticAccess , Expression [ ] args )
20+ public bool ContainsMethod ( Type type , string methodName , bool staticAccess , ref Expression [ ] args )
2121 {
22- return FindMethod ( type , methodName , staticAccess , args , out _ ) == 1 ;
22+ return FindMethod ( type , methodName , staticAccess , ref args , out _ ) == 1 ;
2323 }
2424
25- public int FindMethod ( Type type , string methodName , bool staticAccess , Expression [ ] args , out MethodBase method )
25+ public int FindMethod ( Type type , string methodName , bool staticAccess , ref Expression [ ] args , out MethodBase method )
2626 {
2727#if ! ( NETFX_CORE || WINDOWS_APP || DOTNET5_1 || UAP10_0 || NETSTANDARD )
2828 BindingFlags flags = BindingFlags . Public | BindingFlags . DeclaredOnly | ( staticAccess ? BindingFlags . Static : BindingFlags . Instance ) ;
2929 foreach ( Type t in SelfAndBaseTypes ( type ) )
3030 {
3131 MemberInfo [ ] members = t . FindMembers ( MemberTypes . Method , flags , Type . FilterNameIgnoreCase , methodName ) ;
32- int count = FindBestMethod ( members . Cast < MethodBase > ( ) , args , out method ) ;
32+ int count = FindBestMethod ( members . Cast < MethodBase > ( ) , ref args , out method ) ;
3333 if ( count != 0 )
3434 {
3535 return count ;
@@ -39,7 +39,7 @@ public int FindMethod(Type type, string methodName, bool staticAccess, Expressio
3939 foreach ( Type t in SelfAndBaseTypes ( type ) )
4040 {
4141 MethodInfo [ ] methods = t . GetTypeInfo ( ) . DeclaredMethods . Where ( x => ( x . IsStatic || ! staticAccess ) && x . Name . ToLowerInvariant ( ) == methodName . ToLowerInvariant ( ) ) . ToArray ( ) ;
42- int count = FindBestMethod ( methods , args , out method ) ;
42+ int count = FindBestMethod ( methods , ref args , out method ) ;
4343 if ( count != 0 )
4444 {
4545 return count ;
@@ -50,16 +50,20 @@ public int FindMethod(Type type, string methodName, bool staticAccess, Expressio
5050 return 0 ;
5151 }
5252
53- public int FindBestMethod ( IEnumerable < MethodBase > methods , Expression [ ] args , out MethodBase method )
53+ public int FindBestMethod ( IEnumerable < MethodBase > methods , ref Expression [ ] args , out MethodBase method )
5454 {
55+ // passing args by reference is now required with the params array support.
56+
57+ var inlineArgs = args ;
58+
5559 MethodData [ ] applicable = methods
5660 . Select ( m => new MethodData { MethodBase = m , Parameters = m . GetParameters ( ) } )
57- . Where ( m => IsApplicable ( m , args ) )
61+ . Where ( m => IsApplicable ( m , inlineArgs ) )
5862 . ToArray ( ) ;
5963
6064 if ( applicable . Length > 1 )
6165 {
62- applicable = applicable . Where ( m => applicable . All ( n => m == n || IsBetterThan ( args , m , n ) ) ) . ToArray ( ) ;
66+ applicable = applicable . Where ( m => applicable . All ( n => m == n || IsBetterThan ( inlineArgs , m , n ) ) ) . ToArray ( ) ;
6367 }
6468
6569 if ( args . Length == 2 && applicable . Length > 1 && ( args [ 0 ] . Type == typeof ( Guid ? ) || args [ 1 ] . Type == typeof ( Guid ? ) ) )
@@ -70,11 +74,8 @@ public int FindBestMethod(IEnumerable<MethodBase> methods, Expression[] args, ou
7074 if ( applicable . Length == 1 )
7175 {
7276 MethodData md = applicable [ 0 ] ;
73- for ( int i = 0 ; i < args . Length ; i ++ )
74- {
75- args [ i ] = md . Args [ i ] ;
76- }
7777 method = md . MethodBase ;
78+ args = md . Args ;
7879 }
7980 else
8081 {
@@ -98,7 +99,7 @@ public int FindIndexer(Type type, Expression[] args, out MethodBase method)
9899#else
99100 Select ( p => ( MethodBase ) p . GetMethod ) ;
100101#endif
101- int count = FindBestMethod ( methods , args , out method ) ;
102+ int count = FindBestMethod ( methods , ref args , out method ) ;
102103 if ( count != 0 )
103104 {
104105 return count ;
@@ -112,27 +113,63 @@ public int FindIndexer(Type type, Expression[] args, out MethodBase method)
112113
113114 bool IsApplicable ( MethodData method , Expression [ ] args )
114115 {
115- if ( method . Parameters . Length != args . Length )
116+ // parameter count must be equal or the last one must be a param array
117+ bool isParamArray = method . Parameters . Length > 0 && method . Parameters . Last ( ) . IsDefined ( typeof ( ParamArrayAttribute ) , false ) ;
118+ if ( method . Parameters . Length != args . Length && ! isParamArray )
116119 {
117120 return false ;
118121 }
119122
120- Expression [ ] promotedArgs = new Expression [ args . Length ] ;
121- for ( int i = 0 ; i < args . Length ; i ++ )
123+ Expression [ ] promotedArgs = new Expression [ method . Parameters . Length ] ;
124+ for ( int i = 0 ; i < method . Parameters . Length ; i ++ )
122125 {
123- ParameterInfo pi = method . Parameters [ i ] ;
124- if ( pi . IsOut )
126+ if ( isParamArray && i == method . Parameters . Length - 1 )
125127 {
126- return false ;
127- }
128+ if ( method . Parameters . Length == args . Length + 1
129+ || ( method . Parameters . Length == args . Length && args [ i ] is ConstantExpression constantExpression && constantExpression . Value == null ) )
130+ {
131+ promotedArgs [ promotedArgs . Length - 1 ] = Expression . Constant ( null , method . Parameters . Last ( ) . ParameterType ) ;
132+ }
133+ else
134+ {
135+ var paramType = method . Parameters . Last ( ) . ParameterType ;
136+ var paramElementType = paramType . GetElementType ( ) ;
137+
138+ List < Expression > arrayInitializerExpressions = new List < Expression > ( ) ;
139+
140+ for ( int j = method . Parameters . Length - 1 ; j < args . Length ; j ++ )
141+ {
142+ Expression promoted = this . _parsingConfig . ExpressionPromoter . Promote ( args [ j ] , paramElementType , false , method . MethodBase . DeclaringType != typeof ( IEnumerableSignatures ) ) ;
143+ if ( promoted == null )
144+ {
145+ return false ;
146+ }
128147
129- Expression promoted = this . _parsingConfig . ExpressionPromoter . Promote ( args [ i ] , pi . ParameterType , false , method . MethodBase . DeclaringType != typeof ( IEnumerableSignatures ) ) ;
130- if ( promoted == null )
148+ arrayInitializerExpressions . Add ( promoted ) ;
149+ }
150+
151+ var paramExpression = Expression . NewArrayInit ( paramElementType , arrayInitializerExpressions ) ;
152+
153+ promotedArgs [ promotedArgs . Length - 1 ] = paramExpression ;
154+ }
155+ }
156+ else
131157 {
132- return false ;
158+ ParameterInfo pi = method . Parameters [ i ] ;
159+ if ( pi . IsOut )
160+ {
161+ return false ;
162+ }
163+
164+ Expression promoted = this . _parsingConfig . ExpressionPromoter . Promote ( args [ i ] , pi . ParameterType , false , method . MethodBase . DeclaringType != typeof ( IEnumerableSignatures ) ) ;
165+ if ( promoted == null )
166+ {
167+ return false ;
168+ }
169+ promotedArgs [ i ] = promoted ;
133170 }
134- promotedArgs [ i ] = promoted ;
135171 }
172+
136173 method . Args = promotedArgs ;
137174 return true ;
138175 }
0 commit comments