@@ -279,6 +279,23 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info)
279
279
return Bind ( inst , args , kw , info , null ) ;
280
280
}
281
281
282
+ private readonly struct MatchedMethod {
283
+ public MatchedMethod ( int kwargsMatched , int defaultsNeeded , object [ ] margs , int outs , MethodBase mb )
284
+ {
285
+ KwargsMatched = kwargsMatched ;
286
+ DefaultsNeeded = defaultsNeeded ;
287
+ ManagedArgs = margs ;
288
+ Outs = outs ;
289
+ Method = mb ;
290
+ }
291
+
292
+ public int KwargsMatched { get ; }
293
+ public int DefaultsNeeded { get ; }
294
+ public object [ ] ManagedArgs { get ; }
295
+ public int Outs { get ; }
296
+ public MethodBase Method { get ; }
297
+ }
298
+
282
299
internal Binding Bind ( IntPtr inst , IntPtr args , IntPtr kw , MethodBase info , MethodInfo [ ] methodinfo )
283
300
{
284
301
// loop to find match, return invoker w/ or /wo error
@@ -311,6 +328,8 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
311
328
_methods = GetMethods ( ) ;
312
329
}
313
330
331
+ var argMatchedMethods = new List < MatchedMethod > ( _methods . Length ) ;
332
+
314
333
// TODO: Clean up
315
334
foreach ( MethodBase mi in _methods )
316
335
{
@@ -321,8 +340,10 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
321
340
ParameterInfo [ ] pi = mi . GetParameters ( ) ;
322
341
ArrayList defaultArgList ;
323
342
bool paramsArray ;
343
+ int kwargsMatched ;
344
+ int defaultsNeeded ;
324
345
325
- if ( ! MatchesArgumentCount ( pynargs , pi , kwargDict , out paramsArray , out defaultArgList ) )
346
+ if ( ! MatchesArgumentCount ( pynargs , pi , kwargDict , out paramsArray , out defaultArgList , out kwargsMatched , out defaultsNeeded ) )
326
347
{
327
348
continue ;
328
349
}
@@ -336,6 +357,47 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
336
357
continue ;
337
358
}
338
359
360
+ var matchedMethod = new MatchedMethod ( kwargsMatched , defaultsNeeded , margs , outs , mi ) ;
361
+ argMatchedMethods . Add ( matchedMethod ) ;
362
+ }
363
+ if ( argMatchedMethods . Count > 0 )
364
+ {
365
+ var bestKwargMatchCount = argMatchedMethods . Max ( x => x . KwargsMatched ) ;
366
+ var fewestDefaultsRequired = argMatchedMethods . Where ( x => x . KwargsMatched == bestKwargMatchCount ) . Min ( x => x . DefaultsNeeded ) ;
367
+
368
+ int bestCount = 0 ;
369
+ int bestMatchIndex = - 1 ;
370
+
371
+ for ( int index = 0 ; index < argMatchedMethods . Count ; index ++ )
372
+ {
373
+ var testMatch = argMatchedMethods [ index ] ;
374
+ if ( testMatch . DefaultsNeeded == fewestDefaultsRequired && testMatch . KwargsMatched == bestKwargMatchCount )
375
+ {
376
+ bestCount ++ ;
377
+ if ( bestMatchIndex == - 1 )
378
+ bestMatchIndex = index ;
379
+ }
380
+ }
381
+
382
+ if ( bestCount > 1 && fewestDefaultsRequired > 0 )
383
+ {
384
+ // Best effort for determining method to match on gives multiple possible
385
+ // matches and we need at least one default argument - bail from this point
386
+ return null ;
387
+ }
388
+
389
+ // If we're here either:
390
+ // (a) There is only one best match
391
+ // (b) There are multiple best matches but none of them require
392
+ // default arguments
393
+ // in the case of (a) we're done by default. For (b) regardless of which
394
+ // method we choose, all arguments are specified _and_ can be converted
395
+ // from python to C# so picking any will suffice
396
+ MatchedMethod bestMatch = argMatchedMethods [ bestMatchIndex ] ;
397
+ var margs = bestMatch . ManagedArgs ;
398
+ var outs = bestMatch . Outs ;
399
+ var mi = bestMatch . Method ;
400
+
339
401
object target = null ;
340
402
if ( ! mi . IsStatic && inst != IntPtr . Zero )
341
403
{
@@ -575,11 +637,16 @@ static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool
575
637
static bool MatchesArgumentCount ( int positionalArgumentCount , ParameterInfo [ ] parameters ,
576
638
Dictionary < string , IntPtr > kwargDict ,
577
639
out bool paramsArray ,
578
- out ArrayList defaultArgList )
640
+ out ArrayList defaultArgList ,
641
+ out int kwargsMatched ,
642
+ out int defaultsNeeded )
579
643
{
580
644
defaultArgList = null ;
581
645
var match = false ;
582
646
paramsArray = parameters . Length > 0 ? Attribute . IsDefined ( parameters [ parameters . Length - 1 ] , typeof ( ParamArrayAttribute ) ) : false ;
647
+ var kwargCount = kwargDict . Count ;
648
+ kwargsMatched = 0 ;
649
+ defaultsNeeded = 0 ;
583
650
584
651
if ( positionalArgumentCount == parameters . Length && kwargDict . Count == 0 )
585
652
{
@@ -599,6 +666,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
599
666
// no need to check for a default parameter, but put a null
600
667
// placeholder in defaultArgList
601
668
defaultArgList . Add ( null ) ;
669
+ kwargsMatched ++ ;
602
670
}
603
671
else if ( parameters [ v ] . IsOptional )
604
672
{
@@ -607,6 +675,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
607
675
// The GetDefaultValue() extension method will return the value
608
676
// to be passed in as the parameter value
609
677
defaultArgList . Add ( parameters [ v ] . GetDefaultValue ( ) ) ;
678
+ defaultsNeeded ++ ;
610
679
}
611
680
else if ( ! paramsArray )
612
681
{
0 commit comments