@@ -30,8 +30,8 @@ protected override Assembly Load(AssemblyName assemblyName)
3030        if  ( assemblyName . Name  ==  "TestInterface" ) 
3131        { 
3232            AssemblyLoadContext  alc1  =  new  AssemblyLoadContext ( "Dependencies" ,  true ) ; 
33-             Console . WriteLine ( $ "Loading TestInterface by alc { alc1 }  for alc { this } ") ; 
34-             Assembly  a  =  alc1 . LoadFromAssemblyPath ( Path . Combine ( AppDomain . CurrentDomain . BaseDirectory ,   @"..\TestInterface\TestInterface.dll" ) ) ; 
33+             Console . WriteLine ( $ "Loading TestInterface by alc { alc1 }  for { ( IsCollectible   ?   "collectible"   :   "non-collectible" ) }   alc { this } ") ; 
34+             Assembly  a  =  alc1 . LoadFromAssemblyPath ( Test . GetTestAssemblyPath ( @"..\TestInterface\TestInterface.dll" ) ) ; 
3535            interfaceAssemblyRef  =  new  WeakReference ( a ) ; 
3636            return  a ; 
3737        } 
@@ -45,13 +45,18 @@ class Test
4545    static AssemblyLoadContext  alc1  =  null ; 
4646    static WeakReference  interfaceAssemblyRef  =  null ; 
4747
48+     public  static string  GetTestAssemblyPath ( string  subPath ) 
49+     { 
50+         return  Path . Combine ( Path . GetDirectoryName ( Assembly . GetExecutingAssembly ( ) . Location ) ,  subPath ) ; 
51+     } 
52+ 
4853    [ MethodImpl ( MethodImplOptions . NoInlining ) ] 
49-     public  static Assembly  LoadUsingResolvingEvent ( ) 
54+     private  static Assembly  LoadUsingResolvingEvent ( bool   collectibleParent ) 
5055    { 
5156        alc1  =  new  AssemblyLoadContext ( "Dependencies" ,  true ) ; 
52-         AssemblyLoadContext  alc2  =  new  AssemblyLoadContext ( "Test1" ,  true ) ; 
57+         AssemblyLoadContext  alc2  =  new  AssemblyLoadContext ( "Test1" ,  collectibleParent ) ; 
5358        alc2 . Resolving  +=  Alc2_Resolving ; 
54-         Assembly  assembly  =  alc2 . LoadFromAssemblyPath ( Path . Combine ( AppDomain . CurrentDomain . BaseDirectory ,   @"..\TestClass\TestClass.dll" ) ) ; 
59+         Assembly  assembly  =  alc2 . LoadFromAssemblyPath ( Test . GetTestAssemblyPath ( @"..\TestClass\TestClass.dll" ) ) ; 
5560
5661        Type  t  =  assembly . GetType ( "TestClass.Class" ) ; 
5762        Console . WriteLine ( $ "Type { t }  obtained") ; 
@@ -70,8 +75,8 @@ private static Assembly Alc2_Resolving(AssemblyLoadContext arg1, AssemblyName ar
7075        Console . WriteLine ( $ "Resolving event by alc { alc1 }  for alc { arg1 } ") ; 
7176        if  ( alc1  !=  null  &&  arg2 . Name  ==  "TestInterface" ) 
7277        { 
73-             Console . WriteLine ( $ "Loading TestInterface by alc { alc1 }  for alc { arg1 } ") ; 
74-             Assembly  a  =  alc1 . LoadFromAssemblyPath ( Path . Combine ( AppDomain . CurrentDomain . BaseDirectory ,   @"..\TestInterface\TestInterface.dll" ) ) ; 
78+             Console . WriteLine ( $ "Loading TestInterface by alc { alc1 }  for { ( arg1 . IsCollectible   ?   "collectible"   :   "non-collectible" ) }   alc { arg1 } ") ; 
79+             Assembly  a  =  alc1 . LoadFromAssemblyPath ( Test . GetTestAssemblyPath ( @"..\TestInterface\TestInterface.dll" ) ) ; 
7580            interfaceAssemblyRef  =  new  WeakReference ( a ) ; 
7681            return  a ; 
7782        } 
@@ -80,10 +85,10 @@ private static Assembly Alc2_Resolving(AssemblyLoadContext arg1, AssemblyName ar
8085    } 
8186
8287    [ MethodImpl ( MethodImplOptions . NoInlining ) ] 
83-     public  static Assembly  LoadUsingLoadOverride ( ) 
88+     private  static Assembly  LoadUsingLoadOverride ( bool   collectibleParent ) 
8489    { 
85-         TestAssemblyLoadContext  alc2  =  new  TestAssemblyLoadContext ( "Test2" ,  true ) ; 
86-         Assembly  assembly  =  alc2 . LoadFromAssemblyPath ( Path . Combine ( AppDomain . CurrentDomain . BaseDirectory ,   @"..\TestClass\TestClass.dll" ) ) ; 
90+         TestAssemblyLoadContext  alc2  =  new  TestAssemblyLoadContext ( "Test2" ,  collectibleParent ) ; 
91+         Assembly  assembly  =  alc2 . LoadFromAssemblyPath ( Test . GetTestAssemblyPath ( @"..\TestClass\TestClass.dll" ) ) ; 
8792
8893        Type  t  =  assembly . GetType ( "TestClass.Class" ) ; 
8994
@@ -94,18 +99,33 @@ public static Assembly LoadUsingLoadOverride()
9499        return  assembly ; 
95100    } 
96101
102+     private  enum  TestCase 
103+     { 
104+         ResolvingEvent , 
105+         LoadOverride , 
106+         ResolvingEventInNonCollectible , 
107+         LoadOverrideInNonCollectible 
108+     } 
109+ 
97110    [ MethodImpl ( MethodImplOptions . NoInlining ) ] 
98-     private  static WeakReference  TestDependencies ( string  testCase ) 
111+     private  static WeakReference  TestDependencies ( TestCase  testCase ) 
99112    { 
100-         Assembly  assembly ; 
113+         Assembly  assembly   =   null ; 
101114
102-         if  ( testCase  ==  "ResolvingEvent" ) 
103-         { 
104-             assembly  =  LoadUsingResolvingEvent ( ) ; 
105-         } 
106-         else 
115+         switch  ( testCase ) 
107116        { 
108-             assembly  =  LoadUsingLoadOverride ( ) ; 
117+             case  TestCase . ResolvingEvent : 
118+                 assembly  =  LoadUsingResolvingEvent ( collectibleParent :  true ) ; 
119+                 break ; 
120+             case  TestCase . LoadOverride : 
121+                 assembly  =  LoadUsingLoadOverride ( collectibleParent :  true ) ; 
122+                 break ; 
123+             case  TestCase . ResolvingEventInNonCollectible : 
124+                 assembly  =  LoadUsingResolvingEvent ( collectibleParent :  false ) ; 
125+                 break ; 
126+             case  TestCase . LoadOverrideInNonCollectible : 
127+                 assembly  =  LoadUsingLoadOverride ( collectibleParent :  false ) ; 
128+                 break ; 
109129        } 
110130
111131        for  ( int  i  =  0 ;  interfaceAssemblyRef . IsAlive  &&  ( i  <  10 ) ;  i ++ ) 
@@ -124,45 +144,78 @@ private static WeakReference TestDependencies(string testCase)
124144        return  new  WeakReference ( assembly ) ; 
125145    } 
126146
127-     public  static int   TestFullUnload ( string  testCase ) 
147+     private  static bool   ShouldThrow ( TestCase  testCase ) 
128148    { 
129-         Console . WriteLine ( $ "Running test case { testCase } ") ; 
149+         return  ( testCase  ==  TestCase . LoadOverrideInNonCollectible )  ||  ( testCase  ==  TestCase . ResolvingEventInNonCollectible ) ; 
150+     } 
130151
131-         WeakReference  assemblyRef  =  TestDependencies ( testCase ) ; 
132-         if  ( assemblyRef  ==  null ) 
133-         { 
134-             return  101 ; 
135-         } 
152+     private  static int  TestFullUnload ( TestCase  testCase ) 
153+     { 
154+         Console . WriteLine ( $ "Running test case { testCase } ") ; 
136155
137-         for   ( int   i   =   0 ;   assemblyRef . IsAlive   &&   ( i   <   10 ) ;   i ++ ) 
156+         try 
138157        { 
139-             GC . Collect ( ) ; 
140-             GC . WaitForPendingFinalizers ( ) ; 
158+             WeakReference  assemblyRef  =  TestDependencies ( testCase ) ; 
159+             if  ( assemblyRef  ==  null ) 
160+             { 
161+                 return  101 ; 
162+             } 
163+ 
164+             for  ( int  i  =  0 ;  assemblyRef . IsAlive  &&  ( i  <  10 ) ;  i ++ ) 
165+             { 
166+                 GC . Collect ( ) ; 
167+                 GC . WaitForPendingFinalizers ( ) ; 
168+             } 
169+ 
170+             if  ( assemblyRef . IsAlive ) 
171+             { 
172+                 Console . WriteLine ( "Failed to unload alc2" ) ; 
173+                 return  102 ; 
174+             } 
175+ 
176+             if  ( interfaceAssemblyRef . IsAlive ) 
177+             { 
178+                 Console . WriteLine ( "Failed to unload alc1" ) ; 
179+                 return  103 ; 
180+             } 
181+ 
182+             Console . WriteLine ( ) ; 
141183        } 
142- 
143-         if  ( assemblyRef . IsAlive ) 
184+         catch  ( System . IO . FileLoadException  e ) 
144185        { 
145-             Console . WriteLine ( "Failed to unload alc2" ) ; 
146-             return  102 ; 
186+             if  ( ! ShouldThrow ( testCase ) ) 
187+             { 
188+                 Console . WriteLine ( "Failure - unexpected exception" ) ; 
189+                 return  104 ; 
190+             } 
191+             if  ( ( e . InnerException  ==  null )  ||  e . InnerException . GetType ( )  !=  typeof ( System . NotSupportedException ) ) 
192+             { 
193+                 Console . WriteLine ( $ "Failure - unexpected exception type { e . InnerException } ") ; 
194+                 return  105 ; 
195+             } 
196+ 
197+             return  100 ; 
147198        } 
148199
149-         if  ( interfaceAssemblyRef . IsAlive ) 
200+         if  ( ShouldThrow ( testCase ) ) 
150201        { 
151-             Console . WriteLine ( "Failed to unload alc1 " ) ; 
152-             return  103 ; 
202+             Console . WriteLine ( "Failure - resolved collectible assembly into non-collectible context without throwing exception " ) ; 
203+             return  106 ; 
153204        } 
154205
155-         Console . WriteLine ( ) ; 
156206        return  100 ; 
157-          
158207    } 
159208
160209    public  static int  Main ( string [ ]  args ) 
161210    { 
162211        int  status  =  100 ; 
163-         foreach  ( string  testCase  in  new   string [ ]   { "LoadOverride" ,   "ResolvingEvent" } ) 
212+         foreach  ( TestCase  testCase  in  Enum . GetValues ( typeof ( TestCase ) ) ) 
164213        { 
165214            status  =  TestFullUnload ( testCase ) ; 
215+             if  ( status  !=  100 ) 
216+             { 
217+                 break ; 
218+             } 
166219        } 
167220
168221        return  status ; 
0 commit comments