Module Providers
IModuleBuilderProvider controls where the dynamic type generated for AsyncBlockExpression and EnumerableBlockExpression state machines is emitted. Two built-in implementations are provided.
Interface
public interface IModuleBuilderProvider
{
ModuleBuilder GetModuleBuilder( ModuleKind kind );
}
public enum ModuleKind
{
Async,
Enumerable
}
Built-in Providers
DefaultModuleBuilderProvider
Emits state machine types into a long-lived, non-collectible dynamic assembly. This is the default.
public sealed class DefaultModuleBuilderProvider : IModuleBuilderProvider
{
public static readonly IModuleBuilderProvider Instance;
}
- Assembly lifetime: application lifetime
- Unloadable: no
- Thread-safe: yes
- Suitable for: production use, most scenarios
CollectibleModuleBuilderProvider
Emits state machine types into a collectible AssemblyLoadContext. Types can be unloaded when all references are released, allowing memory to be reclaimed.
public sealed class CollectibleModuleBuilderProvider : IModuleBuilderProvider
{
public static readonly IModuleBuilderProvider Instance;
}
- Assembly lifetime: until all references are released
- Unloadable: yes (via
AssemblyLoadContext) - Thread-safe: yes
- Suitable for: scenarios with many short-lived lambdas, plugin systems, test isolation
Usage
Default (Implicit)
// DefaultModuleBuilderProvider is used automatically -- no configuration needed
var asyncBlock = BlockAsync( Await( someTask ) );
Collectible Assembly
var options = new ExpressionRuntimeOptions
{
ModuleBuilderProvider = CollectibleModuleBuilderProvider.Instance
};
var asyncBlock = BlockAsync(
[result],
Assign( result, Await( someTask ) ),
result,
options
);
Custom Provider
Implement IModuleBuilderProvider to emit types into a specific assembly or to integrate with a custom AssemblyLoadContext:
public class MyModuleBuilderProvider : IModuleBuilderProvider
{
private readonly ModuleBuilder _module;
public MyModuleBuilderProvider( AssemblyBuilder assembly )
{
_module = assembly.DefineDynamicModule( "StateMachines" );
}
public ModuleBuilder GetModuleBuilder( ModuleKind kind ) => _module;
}
var options = new ExpressionRuntimeOptions
{
ModuleBuilderProvider = new MyModuleBuilderProvider( myAssemblyBuilder )
};
Notes
- Each call to
GetModuleBuildermay return the same or a newModuleBuilderdepending on the implementation. The default implementations return the same module for all calls. - In test projects, use
CollectibleModuleBuilderProviderwhen generating many lambda compilations to avoidOutOfMemoryExceptionfrom accumulated dynamic types. ModuleKindis passed to the provider to allow routingAsyncandEnumerablestate machines to different modules if needed.