This is further complicated by the fact that a MethodBuilder and DynamicMethod don't share any common interfaces or base types for generating IL, despite both of them supporting a GetILGenerator() method.
This difficulty in switching between saved codegen and pure runtime codegen led me to add a CodeGen class to Sasa, which can generate code for either case based on a bool parameter. Since no common interface is available for code generation, it also accepts a delegate to which it dispatches for generating the code:
/// Create a dynamic method.
/// <typeparam name="T">The type of the dynamic method to create.</typeparam>
/// <param name="type">The type to which this delegate should be a member.</param>
/// <param name="methodName">The name of the delegate's method.</param>
/// <param name="attributes">The method attributes.</param>
/// <param name="saveAssembly">Flag indicating whether the generated code should be saved to a dll.</param>
/// <param name="generate">A call back that performs the code generation.</param>
/// <returns>An dynamically created instance of the given delegate type.</returns>
public static T Function<T>(
where T : TypeConstraint<Delegate>;
You can also see Sasa's ilrewrite tool at work here with the T : TypeConstraint<Delegate>. This function will generate either a DynamicMethod or a dynamic assembly and save that assembly to disk, based on the 'saveAssembly' parameter. The assembly name is generated based on the type and methodName parameters.
In debugging the Sasa.Dynamics reflection code, I also came across a strange error which was not adequately explained anywhere that I could find. peverify.exe spit out an error to the effect of:
[X.dll : Y/Z][offset 0x0000001D] Unable to resolve token
Where X is the name of the generated dll, Y the namespace path, and Z is the class name. In my case, this occurred when the dynamically generated code was referencing a private class, which should not be possible from a separate dll.