Collectible Assemblies for Dynamic Type Generation
Collectible assemblies are dynamic assemblies that can be unloaded without unloading the application domain in which they were created. All managed and unmanaged memory used by a collectible assembly and the types it contains can be reclaimed. Information such as the assembly name is removed from internal tables.
To enable unloading, use the AssemblyBuilderAccess.RunAndCollect flag when you create a dynamic assembly. The assembly is transient (that is, it cannot be saved) and is subject to limitations described in the Restrictions on Collectible Assemblies section. The common language runtime (CLR) unloads a collectible assembly automatically when you have released all objects associated with the assembly. In all other respects, collectible assemblies are created and used in the same way as other dynamic assemblies.
Lifetime of Collectible Assemblies
The lifetime of a collectible dynamic assembly is controlled by the existence of references to the types it contains, and the objects that are created from those types. The common language runtime does not unload an assembly as long as one or more of the following exist (T is any type that is defined in the assembly):
An instance of T.
An instance of an array of T, or an instance of a generic collection that has T as one of its type arguments, even if that array or collection is empty.
You must release all objects that represent parts of the assembly. The ModuleBuilder that defined T keeps a reference to the TypeBuilder, and the AssemblyBuilder object keeps a reference to the ModuleBuilder, so references to these objects must be released. Even the existence of a LocalBuilder or an ILGenerator used in the construction of T prevents unloading.
A static reference to T by another dynamically defined type T1 that is still reachable by executing code. For example, T1 might derive from T, or T might be the type of a parameter in a method of T1.
A ByRef to a static field that belongs to T.
An instance of any reflection object that could be used indirectly or directly to access the Type object that represents T. For example, the Type object for T can be obtained from an array type whose element type is T, or from a generic type that has T as a type argument.
A method M on the call stack of any thread, where M is a method of T or a module-level method that is defined in the assembly.
A delegate to a static method that is defined in a module of the assembly.
If only one item from this list exists for only one type or one method in the assembly, the runtime cannot unload the assembly.
The runtime does not actually unload the assembly until finalizers have run for all items in the list.
For purposes of tracking lifetime, a constructed generic type such as List<int> (List(Of Integer) in Visual Basic) that is created and used in the generation of a collectible assembly is considered to have been defined either in the assembly that contains the generic type definition or in an assembly that contains the definition of one of its type arguments. The exact assembly that is used is an implementation detail and subject to change.
Restrictions on Collectible Assemblies
The following restrictions apply to collectible assemblies:
Static references Types in an ordinary dynamic assembly cannot have static references to types that are defined in a collectible assembly. For example, if you define an ordinary type that inherits a type in a collectible assembly, a NotSupportedException exception is thrown. A type in a collectible assembly can have static references to a type in another collectible assembly, but this extends the lifetime of the referenced assembly to the lifetime of the referencing assembly.
COM interop No COM interfaces can be defined within a collectible assembly, and no instances of types within a collectible assembly can be converted into COM objects. A type in a collectible assembly cannot serve as a COM callable wrapper (CCW) or runtime callable wrapper (RCW). However, types in collectible assemblies can use objects that implement COM interfaces.
Platform invoke Methods that have the DllImportAttribute attribute will not compile when they are declared within a collectible assembly. The OpCodes.Calli instruction cannot be used in the implementation of a type in a collectible assembly, and such types cannot be marshaled to unmanaged code. However, you can call into native code by using an entry point that is declared in a non-collectible assembly.
Marshaling Objects that are defined in collectible assemblies (in particular, delegates) cannot be marshaled. This is a restriction on all transient emitted types.
Assembly loading Reflection emit is the only mechanism that is supported for loading collectible assemblies. Assemblies that are loaded by any other form of assembly loading cannot be unloaded.
Context-bound objects Context-static variables are not supported. Types in a collectible assembly cannot extend ContextBoundObject. However, code in collectible assemblies can use context-bound objects that are defined elsewhere.
Thread-static data Thread-static variables are not supported.