@@ -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
{
@@ -574,11 +632,16 @@ static Type TryComputeClrArgumentType(Type parameterType, IntPtr argument, bool
574
632
static bool MatchesArgumentCount ( int positionalArgumentCount , ParameterInfo [ ] parameters ,
575
633
Dictionary < string , IntPtr > kwargDict ,
576
634
out bool paramsArray ,
577
- out ArrayList defaultArgList )
635
+ out ArrayList defaultArgList ,
636
+ out int kwargsMatched ,
637
+ out int defaultsNeeded )
578
638
{
579
639
defaultArgList = null ;
580
640
var match = false ;
581
641
paramsArray = parameters . Length > 0 ? Attribute . IsDefined ( parameters [ parameters . Length - 1 ] , typeof ( ParamArrayAttribute ) ) : false ;
642
+ var kwargCount = kwargDict . Count ( ) ;
643
+ kwargsMatched = 0 ;
644
+ defaultsNeeded = 0 ;
582
645
583
646
if ( positionalArgumentCount == parameters . Length )
584
647
{
@@ -598,6 +661,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
598
661
// no need to check for a default parameter, but put a null
599
662
// placeholder in defaultArgList
600
663
defaultArgList . Add ( null ) ;
664
+ kwargsMatched ++ ;
601
665
}
602
666
else if ( parameters [ v ] . IsOptional )
603
667
{
@@ -606,6 +670,7 @@ static bool MatchesArgumentCount(int positionalArgumentCount, ParameterInfo[] pa
606
670
// The GetDefaultValue() extension method will return the value
607
671
// to be passed in as the parameter value
608
672
defaultArgList . Add ( parameters [ v ] . GetDefaultValue ( ) ) ;
673
+ defaultsNeeded ++ ;
609
674
}
610
675
else if ( ! paramsArray )
611
676
{
0 commit comments