@@ -40,10 +40,15 @@ public int Count
4040 }
4141
4242 internal void AddMethod ( MethodBase m )
43+ {
44+ AddMethod ( m , true ) ;
45+ }
46+
47+ internal void AddMethod ( MethodBase m , bool isOriginal )
4348 {
4449 // we added a new method so we have to re sort the method list
4550 init = false ;
46- list . Add ( new MethodInformation ( m , m . GetParameters ( ) ) ) ;
51+ list . Add ( new MethodInformation ( m , m . GetParameters ( ) , isOriginal ) ) ;
4752 }
4853
4954 /// <summary>
@@ -118,7 +123,7 @@ internal static MethodInfo[] MatchParameters(MethodBase[] mi, Type[] tp)
118123 return result . ToArray ( ) ;
119124 }
120125
121- // Given a generic method and the argsTypes previously matched with it,
126+ // Given a generic method and the argsTypes previously matched with it,
122127 // generate the matching method
123128 internal static MethodInfo ResolveGenericMethod ( MethodInfo method , Object [ ] args )
124129 {
@@ -436,6 +441,7 @@ internal Binding Bind(BorrowedReference inst, BorrowedReference args, BorrowedRe
436441 kwArgDict [ keyStr ! ] = new PyObject ( value ) ;
437442 }
438443 }
444+ var hasNamedArgs = kwArgDict != null && kwArgDict . Count > 0 ;
439445
440446 // Fetch our methods we are going to attempt to match and bind too.
441447 var methods = info == null ? GetMethods ( )
@@ -447,9 +453,10 @@ internal Binding Bind(BorrowedReference inst, BorrowedReference args, BorrowedRe
447453 // Relevant method variables
448454 var mi = methodInformation . MethodBase ;
449455 var pi = methodInformation . ParameterInfo ;
456+ // Avoid accessing the parameter names property unless necessary
457+ var paramNames = hasNamedArgs ? methodInformation . ParameterNames : Array . Empty < string > ( ) ;
450458 int pyArgCount = ( int ) Runtime . PyTuple_Size ( args ) ;
451459
452-
453460 // Special case for operators
454461 bool isOperator = OperatorMethod . IsOperatorMethod ( mi ) ;
455462 // Binary operator methods will have 2 CLR args but only one Python arg
@@ -479,6 +486,7 @@ internal Binding Bind(BorrowedReference inst, BorrowedReference args, BorrowedRe
479486 pyArgCount ,
480487 kwArgDict ,
481488 pi ,
489+ paramNames ,
482490 out bool paramsArray ,
483491 out ArrayList defaultArgList ) )
484492 {
@@ -497,8 +505,8 @@ internal Binding Bind(BorrowedReference inst, BorrowedReference args, BorrowedRe
497505 object arg ; // Python -> Clr argument
498506
499507 // Check our KWargs for this parameter
500- bool hasNamedParam = kwArgDict == null ? false : kwArgDict . TryGetValue ( parameter . Name , out tempPyObject ) ;
501- if ( tempPyObject != null )
508+ bool hasNamedParam = kwArgDict == null ? false : kwArgDict . TryGetValue ( paramNames [ paramIndex ] , out tempPyObject ) ;
509+ if ( tempPyObject != null )
502510 {
503511 op = tempPyObject ;
504512 }
@@ -762,10 +770,16 @@ static BorrowedReference HandleParamsArray(BorrowedReference args, int arrayStar
762770 /// This helper method will perform an initial check to determine if we found a matching
763771 /// method based on its parameters count and type <see cref="Bind(IntPtr,IntPtr,IntPtr,MethodBase,MethodInfo[])"/>
764772 /// </summary>
773+ /// <remarks>
774+ /// We required both the parameters info and the parameters names to perform this check.
775+ /// The CLR method parameters info is required to match the parameters count and type.
776+ /// The names are required to perform an accurate match, since the method can be the snake-cased version.
777+ /// </remarks>
765778 private bool CheckMethodArgumentsMatch ( int clrArgCount ,
766779 int pyArgCount ,
767780 Dictionary < string , PyObject > kwargDict ,
768781 ParameterInfo [ ] parameterInfo ,
782+ string [ ] parameterNames ,
769783 out bool paramsArray ,
770784 out ArrayList defaultArgList )
771785 {
@@ -788,7 +802,7 @@ private bool CheckMethodArgumentsMatch(int clrArgCount,
788802 {
789803 // If the method doesn't have all of these kw args, it is not a match
790804 // Otherwise just continue on to see if it is a match
791- if ( ! kwargDict . All ( x => parameterInfo . Any ( pi => x . Key == pi . Name ) ) )
805+ if ( ! kwargDict . All ( x => parameterNames . Any ( paramName => x . Key == paramName ) ) )
792806 {
793807 return false ;
794808 }
@@ -808,7 +822,7 @@ private bool CheckMethodArgumentsMatch(int clrArgCount,
808822 defaultArgList = new ArrayList ( ) ;
809823 for ( var v = pyArgCount ; v < clrArgCount && match ; v ++ )
810824 {
811- if ( kwargDict != null && kwargDict . ContainsKey ( parameterInfo [ v ] . Name ) )
825+ if ( kwargDict != null && kwargDict . ContainsKey ( parameterNames [ v ] ) )
812826 {
813827 // we have a keyword argument for this parameter,
814828 // no need to check for a default parameter, but put a null
@@ -973,14 +987,30 @@ internal virtual NewReference Invoke(BorrowedReference inst, BorrowedReference a
973987 [ Serializable ]
974988 internal class MethodInformation
975989 {
990+ private Lazy < string [ ] > _parametersNames ;
991+
976992 public MethodBase MethodBase { get ; }
977993
978994 public ParameterInfo [ ] ParameterInfo { get ; }
979995
996+ public bool IsOriginal { get ; }
997+
998+ public string [ ] ParameterNames { get { return _parametersNames . Value ; } }
999+
9801000 public MethodInformation ( MethodBase methodBase , ParameterInfo [ ] parameterInfo )
1001+ : this ( methodBase , parameterInfo , true )
1002+ {
1003+ }
1004+
1005+ public MethodInformation ( MethodBase methodBase , ParameterInfo [ ] parameterInfo , bool isOriginal )
9811006 {
9821007 MethodBase = methodBase ;
9831008 ParameterInfo = parameterInfo ;
1009+ IsOriginal = isOriginal ;
1010+
1011+ _parametersNames = new Lazy < string [ ] > ( ( ) => IsOriginal
1012+ ? ParameterInfo . Select ( pi => pi . Name ) . ToArray ( )
1013+ : ParameterInfo . Select ( pi => pi . Name . ToSnakeCase ( ) ) . ToArray ( ) ) ;
9841014 }
9851015
9861016 public override string ToString ( )
0 commit comments