@@ -18,7 +18,7 @@ namespace Python.Runtime
1818 /// </summary>
1919 internal class ClassManager
2020 {
21- private static Dictionary < Type , ClassBase > cache ;
21+ private static Dictionary < MaybeType , ClassBase > cache ;
2222 private static readonly Type dtype ;
2323
2424 private ClassManager ( )
@@ -36,7 +36,7 @@ static ClassManager()
3636
3737 public static void Reset ( )
3838 {
39- cache = new Dictionary < Type , ClassBase > ( 128 ) ;
39+ cache = new Dictionary < MaybeType , ClassBase > ( 128 ) ;
4040 }
4141
4242 internal static void DisposePythonWrappersForClrTypes ( )
@@ -85,26 +85,56 @@ internal static void SaveRuntimeData(RuntimeDataStorage storage)
8585 var contexts = storage . AddValue ( "contexts" ,
8686 new Dictionary < IntPtr , InterDomainContext > ( ) ) ;
8787 storage . AddValue ( "cache" , cache ) ;
88- foreach ( var cls in cache . Values )
88+ foreach ( var cls in cache )
8989 {
90+ if ( ! cls . Key . Valid )
91+ {
92+ // Don't serialize an invalid class
93+ continue ;
94+ }
9095 // This incref is for cache to hold the cls,
9196 // thus no need for decreasing it at RestoreRuntimeData.
92- Runtime . XIncref ( cls . pyHandle ) ;
93- var context = contexts [ cls . pyHandle ] = new InterDomainContext ( ) ;
94- cls . Save ( context ) ;
97+ Runtime . XIncref ( cls . Value . pyHandle ) ;
98+ var context = contexts [ cls . Value . pyHandle ] = new InterDomainContext ( ) ;
99+ cls . Value . Save ( context ) ;
100+
101+ // Remove all members added in InitBaseClass.
102+ // this is done so that if domain reloads and a member of a
103+ // reflected dotnet class is removed, it is removed from the
104+ // Python object's dictionary tool; thus raising an AttributeError
105+ // instead of a TypeError.
106+ // Classes are re-initialized on in RestoreRuntimeData.
107+ IntPtr dict = Marshal . ReadIntPtr ( cls . Value . tpHandle , TypeOffset . tp_dict ) ;
108+ foreach ( var member in cls . Value . dotNetMembers )
109+ {
110+ // No need to decref the member, the ClassBase instance does
111+ // not own the reference.
112+ Runtime . PyDict_DelItemString ( dict , member ) ;
113+ }
114+ // Trying to remove a key that's not in the dictionary may
115+ // raise an error. We don't care about it.
116+ Runtime . PyErr_Clear ( ) ;
95117 }
96118 }
97119
98120 internal static Dictionary < ManagedType , InterDomainContext > RestoreRuntimeData ( RuntimeDataStorage storage )
99121 {
100- cache = storage . GetValue < Dictionary < Type , ClassBase > > ( "cache" ) ;
122+ var _cache = storage . GetValue < Dictionary < MaybeType , ClassBase > > ( "cache" ) ;
101123 var contexts = storage . GetValue < Dictionary < IntPtr , InterDomainContext > > ( "contexts" ) ;
102124 var loadedObjs = new Dictionary < ManagedType , InterDomainContext > ( ) ;
103- foreach ( var cls in cache . Values )
125+ foreach ( var pair in _cache )
104126 {
105- var context = contexts [ cls . pyHandle ] ;
106- cls . Load ( context ) ;
107- loadedObjs . Add ( cls , context ) ;
127+ if ( ! pair . Key . Valid )
128+ {
129+ Runtime . XDecref ( pair . Value . pyHandle ) ;
130+ continue ;
131+ }
132+ // re-init the class
133+ InitClassBase ( pair . Key . Value , pair . Value ) ;
134+ cache . Add ( pair . Key , pair . Value ) ;
135+ var context = contexts [ pair . Value . pyHandle ] ;
136+ pair . Value . Load ( context ) ;
137+ loadedObjs . Add ( pair . Value , context ) ;
108138 }
109139 return loadedObjs ;
110140 }
@@ -209,11 +239,16 @@ private static void InitClassBase(Type type, ClassBase impl)
209239 IntPtr dict = Marshal . ReadIntPtr ( tp , TypeOffset . tp_dict ) ;
210240
211241
242+ if ( impl . dotNetMembers == null )
243+ {
244+ impl . dotNetMembers = new List < string > ( ) ;
245+ }
212246 IDictionaryEnumerator iter = info . members . GetEnumerator ( ) ;
213247 while ( iter . MoveNext ( ) )
214248 {
215249 var item = ( ManagedType ) iter . Value ;
216250 var name = ( string ) iter . Key ;
251+ impl . dotNetMembers . Add ( name ) ;
217252 Runtime . PyDict_SetItemString ( dict , name , item . pyHandle ) ;
218253 // Decref the item now that it's been used.
219254 item . DecrRefCount ( ) ;
@@ -241,7 +276,7 @@ private static void InitClassBase(Type type, ClassBase impl)
241276 // required that the ClassObject.ctors be changed to internal
242277 if ( co != null )
243278 {
244- if ( co . ctors . Length > 0 )
279+ if ( co . NumCtors > 0 )
245280 {
246281 // Implement Overloads on the class object
247282 if ( ! CLRModule . _SuppressOverloads )
0 commit comments