Reputation: 1708
I am trying to use Mono.Cecil (v 0.11.5) to emit an IL assembly as an .EXE, written in C# 12 on .NET 8. Almost all of the information I can find on using Mono.Cecil is for .NET Framework.
If it is relevant, the host machine is Windows 11, with the .NET 8 runtime and SDK installed. I am using Rider, and do not have visual Studio installed.
It is emitting the .EXE file (source of emitter below), and the IL within seems correct.
However, when running the .EXE, I get:
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' or one of its dependencies. The system cannot find the file specified.
How do I make it emit properly for a .NET 8 runtime?
// Slightly modified from:
// https://mycodingplace.wordpress.com/2016/11/10/mono-cecil-hello-world/
public static void Emit()
{
// Create a new assembly
var assembly = AssemblyDefinition.CreateAssembly(
new AssemblyNameDefinition("HelloWorld", new Version()),
"HelloWorld",
ModuleKind.Console);
// This is the main module you need to work with
var module = assembly.MainModule;
// Create a new type called "Program" and add it to main module
var programType = new TypeDefinition(
"HelloWorld",
"Program",
TypeAttributes.Class | TypeAttributes.Public,
module.Import(typeof(object)));
module.Types.Add(programType);
// create a new method called 'Main' method and add it to 'Program' type
var mainMethod = new MethodDefinition(
"Main",
MethodAttributes.Public | MethodAttributes.Static,
module.Import(typeof(void)));
programType.Methods.Add(mainMethod);
// Get ILProcessor for the method body
var ilProcessor = mainMethod.Body.GetILProcessor();
// Load the string "Hello World" to stack
ilProcessor.Emit(OpCodes.Ldstr, "Hello World");
// Call Console.WrtieLine(string)
var writline = module.ImportReference(
typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
ilProcessor.Emit(OpCodes.Call, writline);
// Call Console.ReadKey()
var readKey = module.ImportReference(typeof(Console).GetMethod("Read"));
ilProcessor.Emit(OpCodes.Call, readKey);
// You must pop out the return value before you leave the method
ilProcessor.Emit(OpCodes.Pop);
// Return
ilProcessor.Emit(OpCodes.Ret);
// Because this is an executable assembly, you must define an entry point
assembly.EntryPoint = mainMethod;
// Save the assembly to disk
assembly.Write(@"c:\temp\HelloWorld.exe");
}
Upvotes: 1
Views: 80