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

.NET中使用Roslyn编译内存程序集时,将内存程序集作为元数据引用引发ImageNotFoundException的问题

.NET中使用Roslyn编译内存程序集时,将内存程序集作为元数据引用引发ImageNotFoundException的问题

我来帮你解决这个问题!你遇到的这个报错,核心原因其实是CLR运行时找不到你的引用程序集——虽然Roslyn编译主程序集的时候,通过内存流拿到了引用程序集的元数据,但编译完成后,主程序集里只记录了依赖程序集的名称,运行时CLR默认只会去磁盘、GAC或者已经加载到当前应用程序域的程序集列表里找,而你的MyReference.dll只存在内存流里,既没写入磁盘,也没被加载到应用程序域,所以就抛出了ImageNotFoundException。

下面给你两种实用的解决方案,任选其一都能解决问题:

方案一:提前将引用程序集加载到应用程序域

这种方法最简单直接——先把你编译出来的引用程序集加载到当前AppDomain,然后用加载后的Assembly对象创建MetadataReference。这样主程序集运行时,CLR就能直接找到已经加载的引用程序集,不会再去磁盘找了。

修改你的Main方法如下:

static void Main(string[] args)
{
    var referenceBytes = CompileCSharp(
        "MyReference", // 这里可以去掉.dll后缀,用程序集名称更规范
        """
        public class IdentityProvider
        {
            public T Identity<T>(T x) => x;
        }
        """);

    // 关键步骤:先把引用程序集加载到当前AppDomain
    var referenceAssembly = Assembly.Load(referenceBytes.ToArray());
    // 用已加载的Assembly创建MetadataReference
    var reference = MetadataReference.CreateFromAssembly(referenceAssembly);

    var mainAssembly = CompileCSharp(
        "Main",
        """
        using System;
        public class Program
        {
            public static void Main()
            {
                var provider = new IdentityProvider();
                Console.WriteLine(provider.Identity(123));
            }
        }
        """,
        reference);

    var asm = Assembly.Load(mainAssembly.ToArray());
    asm.GetType("Program")!.GetMethod("Main")!.Invoke(null, null);
}

方案二:注册AssemblyResolve事件,手动提供内存中的程序集

如果你不想提前加载引用程序集,可以利用CLR的AssemblyResolve事件——当CLR找不到某个程序集时,会触发这个事件,你可以在事件处理方法里手动从内存中加载对应的程序集字节。

修改后的Main方法如下:

static void Main(string[] args)
{
    var referenceBytes = CompileCSharp(
        "MyReference.dll",
        """
        public class IdentityProvider
        {
            public T Identity<T>(T x) => x;
        }
        """);

    // 注册AssemblyResolve事件,处理MyReference.dll的加载请求
    AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
    {
        var requestedAssembly = new AssemblyName(args.Name);
        // 匹配请求的程序集名称
        if (requestedAssembly.Name.Equals("MyReference", StringComparison.OrdinalIgnoreCase))
        {
            // 从内存流中加载并返回程序集
            return Assembly.Load(referenceBytes.ToArray());
        }
        // 其他程序集请求返回null,让CLR继续默认逻辑
        return null;
    };

    var reference = MetadataReference.CreateFromStream(referenceBytes);

    var mainAssembly = CompileCSharp(
        "Main.dll",
        """
        using System;
        public class Program
        {
            public static void Main()
            {
                var provider = new IdentityProvider();
                Console.WriteLine(provider.Identity(123));
            }
        }
        """,
        reference);

    var asm = Assembly.Load(mainAssembly.ToArray());
    asm.GetType("Program")!.GetMethod("Main")!.Invoke(null, null);
}

补充说明

  • 两种方案在.NET 7环境下都能正常工作,如果你用的是.NET Core/.NET 5+,也可以考虑用AssemblyLoadContext做更精细的加载隔离,不过上面两种方法已经足够解决你的问题。
  • 方案一的优势是简单直接,但引用程序集会一直留在AppDomain内存中;方案二更灵活,只有当主程序集真正需要时才加载引用程序集。

备注:内容来源于stack exchange,提问作者Peter Lenkefi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 12:48:12