Using .NET 4.7.2, I dynamically generate a .dll at runtime using
internal class Program
{
private static void Main(string[] args)
{
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("MyAssembly"), AssemblyBuilderAccess.RunAndSave);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("ModuleName");
TypeBuilder typeBuilder = moduleBuilder.DefineType("MyNamespace.TypeName", TypeAttributes.Public);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
// Build the method 'public int ReturnTheAnswer() => 42;'.
MethodBuilder newMethod = typeBuilder.DefineMethod("ReturnTheAnswer", MethodAttributes.Public, typeof(int), new Type[0]);
ILGenerator ilGen = newMethod.GetILGenerator();
ilGen.Emit(OpCodes.Ldc_I4_S, 42);
ilGen.Emit(OpCodes.Ret);
Type newType = typeBuilder.CreateType();
assemblyBuilder.Save("MyAssembly.dll"); // Save the assembly in the programs work directory ('bin\Debug').
dynamic o = Activator.CreateInstance(newType); // Create an instance of the dynamically created type.
int r = (int) o.ReturnTheAnswer();
Debug.Assert(r == 42); // If this doesn't fail, the type has been built correctly, is in fact in the .dll and can be used perfectly fine.
}
}
and I can use the type in the .dll perfectly fine, however, when browsing the generated .dll with DotPeek and IL Spy, they both do not show any namespaces or types (albeit they should show the type TypeName in namespace MyNamespace).
Why is the assembly seemingly empty when using two distinct decompilers, but using its types from code works perfectly fine?
(above example code is mvce, you should be able to reproduce the exact behavior I encounter)
Your Type doesn't get saved because it is declared in a transient dynamic module.
AssemblyBuilder'sSavemethod only saves non-transient dynamic modules.See the remarks.
To persist your Type, you must declare it in a non-transient persistable dynamic module, using one of the overloads of
DefineDynamicModulethat accepts afileNameargument, like this:Your full code will look like here below.
Use the same filename to keep your Type and the manifest together in 1 single assembly file.