1
1
using System ;
2
2
using System . Collections ;
3
+ using System . Collections . Concurrent ;
3
4
using System . Diagnostics ;
5
+ using System . Linq ;
4
6
using System . Reflection ;
5
7
using System . Text ;
6
8
using System . Collections . Generic ;
7
9
using System . Linq ;
8
10
9
11
namespace Python . Runtime
10
12
{
11
- using System . Linq ;
12
-
13
13
/// <summary>
14
14
/// A MethodBinder encapsulates information about a (possibly overloaded)
15
15
/// managed method, and is responsible for selecting the right method given
@@ -180,14 +180,7 @@ IPyArgumentConverter GetArgumentConverter() {
180
180
Type converterType = null ;
181
181
foreach ( MethodBase method in this . methods )
182
182
{
183
- var attribute = method . DeclaringType ?
184
- . GetCustomAttributes ( typeof ( PyArgConverterAttribute ) , inherit : false )
185
- . OfType < PyArgConverterAttribute > ( )
186
- . SingleOrDefault ( )
187
- ?? method . DeclaringType ? . Assembly
188
- . GetCustomAttributes ( typeof ( PyArgConverterAttribute ) , inherit : false )
189
- . OfType < PyArgConverterAttribute > ( )
190
- . SingleOrDefault ( ) ;
183
+ PyArgConverterAttribute attribute = TryGetArgConverter ( method . DeclaringType ) ;
191
184
if ( converterType == null )
192
185
{
193
186
if ( attribute == null ) continue ;
@@ -203,6 +196,23 @@ IPyArgumentConverter GetArgumentConverter() {
203
196
return converter ?? DefaultPyArgumentConverter . Instance ;
204
197
}
205
198
199
+ static readonly ConcurrentDictionary < Type , PyArgConverterAttribute > ArgConverterCache =
200
+ new ConcurrentDictionary < Type , PyArgConverterAttribute > ( ) ;
201
+ static PyArgConverterAttribute TryGetArgConverter ( Type type ) {
202
+ if ( type == null ) return null ;
203
+
204
+ return ArgConverterCache . GetOrAdd ( type , declaringType =>
205
+ declaringType
206
+ . GetCustomAttributes ( typeof ( PyArgConverterAttribute ) , inherit : false )
207
+ . OfType < PyArgConverterAttribute > ( )
208
+ . SingleOrDefault ( )
209
+ ?? declaringType . Assembly
210
+ . GetCustomAttributes ( typeof ( PyArgConverterAttribute ) , inherit : false )
211
+ . OfType < PyArgConverterAttribute > ( )
212
+ . SingleOrDefault ( )
213
+ ) ;
214
+ }
215
+
206
216
/// <summary>
207
217
/// Precedence algorithm largely lifted from Jython - the concerns are
208
218
/// generally the same so we'll start with this and tweak as necessary.
@@ -481,97 +491,6 @@ object[] TryConvertArguments(ParameterInfo[] pi, bool paramsArray,
481
491
return margs ;
482
492
}
483
493
484
- internal static bool TryConvertArgument ( IntPtr op , Type parameterType , bool needsResolution ,
485
- out object arg , out bool isOut )
486
- {
487
- arg = null ;
488
- isOut = false ;
489
- var clrtype = TryComputeClrArgumentType ( parameterType , op , needsResolution : needsResolution ) ;
490
- if ( clrtype == null )
491
- {
492
- return false ;
493
- }
494
-
495
- if ( ! Converter . ToManaged ( op , clrtype , out arg , false ) )
496
- {
497
- Exceptions . Clear ( ) ;
498
- return false ;
499
- }
500
-
501
- isOut = clrtype . IsByRef ;
502
- return true ;
503
- }
504
-
505
- static Type TryComputeClrArgumentType ( Type parameterType , IntPtr argument , bool needsResolution )
506
- {
507
- // this logic below handles cases when multiple overloading methods
508
- // are ambiguous, hence comparison between Python and CLR types
509
- // is necessary
510
- Type clrtype = null ;
511
- IntPtr pyoptype ;
512
- if ( needsResolution )
513
- {
514
- // HACK: each overload should be weighted in some way instead
515
- pyoptype = Runtime . PyObject_Type ( argument ) ;
516
- Exceptions . Clear ( ) ;
517
- if ( pyoptype != IntPtr . Zero )
518
- {
519
- clrtype = Converter . GetTypeByAlias ( pyoptype ) ;
520
- }
521
- Runtime . XDecref ( pyoptype ) ;
522
- }
523
-
524
- if ( clrtype != null )
525
- {
526
- var typematch = false ;
527
- if ( ( parameterType != typeof ( object ) ) && ( parameterType != clrtype ) )
528
- {
529
- IntPtr pytype = Converter . GetPythonTypeByAlias ( parameterType ) ;
530
- pyoptype = Runtime . PyObject_Type ( argument ) ;
531
- Exceptions . Clear ( ) ;
532
- if ( pyoptype != IntPtr . Zero )
533
- {
534
- if ( pytype != pyoptype )
535
- {
536
- typematch = false ;
537
- }
538
- else
539
- {
540
- typematch = true ;
541
- clrtype = parameterType ;
542
- }
543
- }
544
- if ( ! typematch )
545
- {
546
- // this takes care of enum values
547
- TypeCode argtypecode = Type . GetTypeCode ( parameterType ) ;
548
- TypeCode paramtypecode = Type . GetTypeCode ( clrtype ) ;
549
- if ( argtypecode == paramtypecode )
550
- {
551
- typematch = true ;
552
- clrtype = parameterType ;
553
- }
554
- }
555
- Runtime . XDecref ( pyoptype ) ;
556
- if ( ! typematch )
557
- {
558
- return null ;
559
- }
560
- }
561
- else
562
- {
563
- typematch = true ;
564
- clrtype = parameterType ;
565
- }
566
- }
567
- else
568
- {
569
- clrtype = parameterType ;
570
- }
571
-
572
- return clrtype ;
573
- }
574
-
575
494
static bool MatchesArgumentCount ( int positionalArgumentCount , ParameterInfo [ ] parameters ,
576
495
Dictionary < string , IntPtr > kwargDict ,
577
496
out bool paramsArray ,
0 commit comments