8000 ensure Python types continue to exist when registered decoders for th… · pythonnet/pythonnet@e31f7ba · GitHub
[go: up one dir, main page]

Skip to content

Commit e31f7ba

Browse files
committed
ensure Python types continue to exist when registered decoders for them are cached
1 parent d0a6f44 commit e31f7ba

File tree

1 file changed

+16
-16
lines changed

1 file changed

+16
-16
lines changed

src/runtime/converterextensions.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -106,36 +106,34 @@ static IPyObjectEncoder[] GetEncoders(Type type)
106106
#endregion
107107

108108
#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)
113111
{
114112
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));
116114
if (targetType == null) throw new ArgumentNullException(nameof(targetType));
117115

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));
119118
result = null;
120119
if (decoder == null) return false;
121120
return decoder.Invoke(pyHandle, out result);
122121
}
123122

124-
static Converter.TryConvertFromPythonDelegate? GetDecoder(IntPtr sourceType, Type targetType)
123+
static (PyType, Converter.TryConvertFromPythonDelegate?) GetDecoder(IntPtr sourceType, Type targetType)
125124
{
126-
IPyObjectDecoder decoder;
127125
var sourceTypeRef = new BorrowedReference(sourceType);
128126
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)
130131
{
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;
136134
}
137135

138-
var decode = genericDecode.MakeGenericMethod(targetType);
136+
var decode = genericDecode.MakeGenericMethod(targetType)!;
139137

140138
bool TryDecode(BorrowedReference pyHandle, out object? result)
141139
{
@@ -151,7 +149,9 @@ bool TryDecode(BorrowedReference pyHandle, out object? result)
151149
return success;
152150
}
153151

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);
155155
}
156156

157157
static readonly MethodInfo genericDecode = typeof(IPyObjectDecoder).GetMethod(nameof(IPyObjectDecoder.TryDecode));

0 commit comments

Comments
 (0)
0