You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Mono.Cecil生成.NET 8 HelloWorld IL程序时加载System.Private.CoreLib失败

问题:生成的.NET 8 IL可执行程序运行时抛出FileNotFoundException

环境:Windows 11系统,已安装.NET 8 SDK与运行时,使用Rider开发,通过Mono.Cecil v0.11.5生成IL程序(代码基于旧.NET Framework示例修改)。

生成的EXE文件运行时抛出异常:

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.

原生成代码如下:

// 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");
}

适配.NET 8运行时的修改方案

原代码默认生成.NET Framework兼容的程序集格式,要适配.NET 8需做以下核心调整:

1. 指定运行时版本与目标框架属性

给模块添加.NET 8的运行时版本标识,并为程序集添加TargetFrameworkAttribute明确目标框架:

// 设置模块运行时版本为.NET 8
module.RuntimeVersion = "v8.0";

// 添加TargetFrameworkAttribute,指定目标框架为net8.0
var targetFrameworkAttrType = module.ImportReference(typeof(System.Runtime.Versioning.TargetFrameworkAttribute));
var targetFrameworkCtor = targetFrameworkAttrType.Resolve().GetConstructors().First();
var targetFrameworkAttr = new CustomAttribute(module.ImportReference(targetFrameworkCtor));
targetFrameworkAttr.ConstructorArguments.Add(new CustomAttributeArgument(module.TypeSystem.String, "net8.0"));
assembly.CustomAttributes.Add(targetFrameworkAttr);

2. 明确入口点标记(可选但规范)

给Main方法添加IsEntryPoint标记,与程序集入口点设置形成双重确认:

mainMethod.IsEntryPoint = true;

3. 使用.NET Core兼容的写入选项

写入程序集时指定符合.NET Core规范的参数,避免生成旧格式PE文件:

assembly.Write(@"c:\temp\HelloWorld.exe", new WriterParameters
{
    WriteSymbols = false // 按需决定是否写入符号文件
});

修改后的完整代码

public static void Emit()
{
    // 创建新程序集
    var assembly = AssemblyDefinition.CreateAssembly(
        new AssemblyNameDefinition("HelloWorld", new Version(1, 0, 0, 0)),
        "HelloWorld",
        ModuleKind.Console);

    var module = assembly.MainModule;
    // 设置运行时版本为.NET 8
    module.RuntimeVersion = "v8.0";

    // 添加TargetFrameworkAttribute,指定net8.0
    var targetFrameworkAttrType = module.ImportReference(typeof(System.Runtime.Versioning.TargetFrameworkAttribute));
    var targetFrameworkCtor = targetFrameworkAttrType.Resolve().GetConstructors().First();
    var targetFrameworkAttr = new CustomAttribute(module.ImportReference(targetFrameworkCtor));
    targetFrameworkAttr.ConstructorArguments.Add(new CustomAttributeArgument(module.TypeSystem.String, "net8.0"));
    assembly.CustomAttributes.Add(targetFrameworkAttr);

    // 创建Program类
    var programType = new TypeDefinition(
        "HelloWorld",
        "Program",
        TypeAttributes.Class | TypeAttributes.Public,
        module.Import(typeof(object)));
    module.Types.Add(programType);

    // 创建Main方法并标记为入口点
    var mainMethod = new MethodDefinition(
        "Main",
        MethodAttributes.Public | MethodAttributes.Static,
        module.Import(typeof(void)));
    mainMethod.IsEntryPoint = true;
    programType.Methods.Add(mainMethod);

    var ilProcessor = mainMethod.Body.GetILProcessor();

    // 加载字符串并调用Console.WriteLine
    ilProcessor.Emit(OpCodes.Ldstr, "Hello World");
    var writeLineMethod = typeof(Console).GetMethod("WriteLine", new[] { typeof(string) });
    var writeline = module.ImportReference(writeLineMethod);
    ilProcessor.Emit(OpCodes.Call, writeline);

    // 调用Console.Read()并弹出返回值
    var readMethod = typeof(Console).GetMethod("Read");
    var read = module.ImportReference(readMethod);
    ilProcessor.Emit(OpCodes.Call, read);
    ilProcessor.Emit(OpCodes.Pop);

    // 返回
    ilProcessor.Emit(OpCodes.Ret);

    // 设置程序集入口点
    assembly.EntryPoint = mainMethod;

    // 写入程序集
    assembly.Write(@"c:\temp\HelloWorld.exe", new WriterParameters
    {
        WriteSymbols = false
    });
}

验证步骤

  1. 生成EXE后,通过dotnet --info确认.NET 8运行时已正确安装
  2. 直接双击EXE或在命令行执行dotnet c:\temp\HelloWorld.exe测试运行

内容的提问来源于stack exchange,提问作者SAJ14SAJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 04:47:14