@@ -106,36 +106,34 @@ static IPyObjectEncoder[] GetEncoders(Type type)
106
106
#endregion
107
107
108
108
#region Decoding
109
- static readonly ConcurrentDictionary < TypePair , Converter . TryConvertFromPythonDelegate ? > pythonToClr = new ( ) ;
110
- internal static bool TryDecode ( BorrowedReference value , BorrowedReference type , Type targetType , out object ? result )
111
- => TryDecode ( value , type . DangerousGetAddress ( ) , targetType , out result ) ;
112
- internal static bool TryDecode ( BorrowedReference pyHandle , IntPtr pyType , Type targetType , out object ? result )
109
+ static readonly ConcurrentDictionary < TypePair , ( PyType , Converter . TryConvertFromPythonDelegate ? ) > pythonToClr = new ( ) ;
110
+ internal static bool TryDecode ( BorrowedReference pyHandle , BorrowedReference pyType , Type targetType , out object ? result )
113
111
{
114
112
if ( pyHandle == null ) throw new ArgumentNullException ( nameof ( pyHandle ) ) ;
115
- if ( pyType == IntPtr . Zero ) throw new ArgumentNullException ( nameof ( pyType ) ) ;
113
+ if ( pyType == null ) throw new ArgumentNullException ( nameof ( pyType ) ) ;
116
114
if ( targetType == null ) throw new ArgumentNullException ( nameof ( targetType ) ) ;
117
115
118
- var decoder = pythonToClr . GetOrAdd ( new TypePair ( pyType , targetType ) , pair => GetDecoder ( pair . PyType , pair . ClrType ) ) ;
116
+ var key = new TypePair ( pyType . DangerousGetAddress ( ) , targetType ) ;
117
+ var ( _, decoder ) = pythonToClr . GetOrAdd ( key , pair => GetDecoder ( pair . PyType , pair . ClrType ) ) ;
119
118
result = null ;
120
119
if ( decoder == null ) return false ;
121
120
return decoder . Invoke ( pyHandle , out result ) ;
122
121
}
123
122
124
- static Converter . TryConvertFromPythonDelegate ? GetDecoder ( IntPtr sourceType , Type targetType )
123
+ static ( PyType , Converter . TryConvertFromPythonDelegate ? ) GetDecoder ( IntPtr sourceType , Type targetType )
125
124
{
126
- IPyObjectDecoder decoder ;
127
125
var sourceTypeRef = new BorrowedReference ( sourceType ) ;
128
126
Debug . Assert ( PyType . IsType ( sourceTypeRef ) ) ;
129
- using ( var pyType = new PyType ( sourceTypeRef , prevalidated : true ) )
127
+ var pyType = new PyType ( sourceTypeRef , prevalidated : true ) ;
128
+
129
+ IPyObjectDecoder decoder ;
130
+ lock ( decoders )
130
131
{
131
- lock ( decoders )
132
- {
133
- decoder = decoders . GetDecoder ( pyType , targetType ) ;
134
- if ( decoder == null ) return null ;
135
- }
132
+ decoder = decoders . GetDecoder ( pyType , targetType ) ;
133
+ if ( decoder == null ) return default ;
136
134
}
137
135
138
- var decode = genericDecode . MakeGenericMethod ( targetType ) ;
136
+ var decode = genericDecode . MakeGenericMethod ( targetType ) ! ;
139
137
140
138
bool TryDecode ( BorrowedReference pyHandle , out object ? result )
141
139
{
@@ -151,7 +149,9 @@ bool TryDecode(BorrowedReference pyHandle, out object? result)
151
149
return success ;
152
150
}
153
151
154
- return TryDecode ;
152
+ // returning PyType here establishes strong reference to the object,
153
+ // that ensures the PyType we use as the converter cache key is not deallocated
154
+ return ( pyType , TryDecode ) ;
155
155
}
156
156
157
157
static readonly MethodInfo genericDecode = typeof ( IPyObjectDecoder ) . GetMethod ( nameof ( IPyObjectDecoder . TryDecode ) ) ;
0 commit comments