@@ -310,6 +310,11 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
310
310
_methods = GetMethods ( ) ;
311
311
}
312
312
313
+ // List of tuples containing methods that have matched based on arguments.
314
+ // Format of tuple is: Number of kwargs matched, defaults needed, margs, outs, method base for matched method
315
+ List < Tuple < int , int , object [ ] , int , MethodBase > > argMatchedMethods =
316
+ new List < Tuple < int , int , object [ ] , int , MethodBase > > ( _methods . Length ) ;
317
+
313
318
// TODO: Clean up
314
319
foreach ( MethodBase mi in _methods )
315
320
{
@@ -320,8 +325,10 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
320
325
ParameterInfo [ ] pi = mi . GetParameters ( ) ;
321
326
ArrayList defaultArgList ;
322
327
bool paramsArray ;
328
+ int kwargsMatched ;
329
+ int defaultsNeeded ;
323
330
324
- if ( ! MatchesArgumentCount ( pynargs , pi , kwargDict , out paramsArray , out defaultArgList ) )
331
+ if ( ! MatchesArgumentCount ( pynargs , pi , kwargDict , out paramsArray , out defaultArgList , out kwargsMatched , out defaultsNeeded ) )
325
332
{
326
333
continue ;
327
334
}
@@ -335,6 +342,57 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth
335
342
continue ;
336
343
}
337
344
345
+ var matchedMethodTuple = Tuple . Create ( kwargsMatched , defaultsNeeded , margs , outs , mi ) ;
346
+ argMatchedMethods . Add ( matchedMethodTuple ) ;
347
+ }
348
+ if ( argMatchedMethods . Count ( ) > 0 )
349
+ {
350
+ // Order matched methods by number of kwargs matched and get the max possible number
351
+ // of kwargs matched
352
+ var bestKwargMatchCount = argMatchedMethods . OrderBy ( ( x ) => x . Item1 ) . Reverse ( ) . ToArray ( ) [ 0 ] . Item1 ;
353
+
354
+ List < Tuple < int , int , object [ ] , int , MethodBase > > bestKwargMatches =
355
+ new List < Tuple < int , int , object [ ] , int , MethodBase > > ( argMatchedMethods . Count ( ) ) ;
356
+ foreach ( Tuple < int , int , object [ ] , int , MethodBase > argMatchedTuple in argMatchedMethods )
357
+ {
358
+ if ( argMatchedTuple . Item1 == bestKwargMatchCount )
359
+ {
360
+ bestKwargMatches . Add ( argMatchedTuple ) ;
361
+ }
362
+ }
363
+
364
+ // Order by the number of defaults required and find the smallest
365
+ var fewestDefaultsRequired = bestKwargMatches . OrderBy ( ( x ) => x . Item2 ) . ToArray ( ) [ 0 ] . Item2 ;
366
+
367
+ List < Tuple < int , int , object [ ] , int , MethodBase > > bestDefaultsMatches =
368
+ new List < Tuple < int , int , object [ ] , int , MethodBase > > ( bestKwargMatches . Count ( ) ) ;
369
+ foreach ( Tuple < int , int , object [ ] , int , MethodBase > testTuple in bestKwargMatches )
370
+ {
371
+ if ( testTuple . Item2 == fewestDefaultsRequired )
372
+ {
373
+ bestDefaultsMatches . Add ( testTuple ) ;
374
+ }
375
+ }
376
+
377
+ if ( bestDefaultsMatches . Count ( ) > 1 && fewestDefaultsRequired > 0 )
378
+ {
379
+ // Best effort for determining method to match on gives multiple possible
380
+ // matches and we need at least one default argument - bail from this point
381
+ return null ;
382
+ }
383
+
384
+ // If we're here either:
385
+ // (a) There is only one best match
386
+ // (b) There are multiple best matches but none of them require
387
+ // default arguments
388
+ // in the case of (a) we're done by default. For (b) regardless of which
389
+ // method we choose, all arguments are specified _and_ can be converted
390
+ // from python to C# so picking any will suffice
391
+ Tuple < int , int , object [ ] , int , MethodBase > bestMatch = bestDefaultsMatches . ToArray ( ) [ 0 ] ;
392
+ var margs = bestMatch . Item3 ;
393
+ var outs = bestMatch . Item4 ;
394
+ var mi = bestMatch . Item5 ;
395
+
338
396
object target = null ;
339
397
if ( ! mi . IsStatic && inst != IntPtr . Zero )
340
398
{
@@ -539,11 +597,16 @@ static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool
539
597
static bool MatchesArgumentCount ( int positionalArgumentCount , ParameterInfo [ ] parameters ,
540
598
Dictionary < string , IntPtr > kwargDict ,
541
599
out bool paramsArray ,
542
- out ArrayList defaultArgList )
600
+ out ArrayList defaultArgList ,
601
+ out int kwargsMatched ,
602
+ out int defaultsNeeded )
543
603
{
544
604
defaultArgList = null ;
545
605
var match = false ;
546
606
paramsArray = false ;
607
+ var kwargCount = kwargDict . Count ( ) ;
608
+ kwargsMatched = 0 ;
609
+ defaultsNeeded = 0 ;
547
610
548
611
if ( positionalArgumentCount == parameters . Length )
549
612
{
@@ -563,6 +626,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
563
626
// no need to check for a default parameter, but put a null
564
627
// placeholder in defaultArgList
565
628
defaultArgList . Add ( null ) ;
629
+ kwargsMatched ++ ;
566
630
}
567
631
else if ( parameters [ v ] . IsOptional )
568
632
{
@@ -571,6 +635,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
571
635
// The GetDefaultValue() extension method will return the value
572
636
// to be passed in as the parameter value
573
637
defaultArgList . Add ( parameters [ v ] . GetDefaultValue ( ) ) ;
638
+ defaultsNeeded ++ ;
574
639
}
575
640
else
576
641
{
0 commit comments