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

C# 跨类调用Assembly.ReflectionOnlyLoadFrom加载DLL抛出异常问题

问题根因

问题完全出在Marshaller类上多余的[Serializable]特性,和反射加载上下文的封送逻辑冲突:

  • Assembly.ReflectionOnlyLoadFrom()会把目标DLL加载到独立的仅反射加载上下文,和程序默认运行的执行上下文完全隔离,返回的Assembly实例是绑定在这个反射上下文里的对象,不能直接跨上下文传递。
  • 给类加[Serializable]标记后,运行时会认为这个类的方法调用可能存在跨应用域/跨上下文的序列化传递场景,因此在LoadAssembly()方法执行完返回结果时,不会直接把对象引用交回给调用方,而是会尝试对返回的Assembly对象做跨上下文封送。这个封送过程会跑到默认执行上下文里重新找目标DLL,不会复用反射上下文里已经加载好的程序集,自然就会抛出文件找不到的异常。
  • 这个封送步骤是在LoadAssembly()方法内部代码执行完、控制权返回给调用方的瞬间触发的,所以异常不会落在方法里的ReflectionOnlyLoadFrom那行,只会落在调用方接收返回值的Assembly assembly = marshaller.LoadAssembly();这行。
  • 把加载逻辑直接写在Loader类里时,调用栈上没有序列化带来的上下文边界,返回的Assembly直接在当前上下文用,不会触发额外的解析逻辑,所以能正常跑。
  • 清理解决方案、重新生成这类操作只处理编译产物,根本碰不到运行时的上下文封送逻辑,当然解决不了问题。
修复方法

选任意一种即可,优先选第一种:

  • 直接删掉Marshaller类上的[Serializable]特性:这个类没有任何跨应用域、跨上下文序列化的使用场景,这个特性纯属多余。删掉之后上下文封送边界消失,代码行为和直接把逻辑写在Loader里完全一致:
public class Marshaller {
    internal Assembly LoadAssembly() {
        return Assembly.ReflectionOnlyLoadFrom("C:\\Users\\OLNO\\Downloads\\SkinProject1.dll");
    }
}
  • 如果确实有需求要保留[Serializable]特性(比如后续要跨AppDomain传递Marshaller实例),就不要直接返回仅反射上下文的Assembly对象,改成返回目标DLL的完整路径字符串,在调用方所在的上下文再执行加载,避免跨上下文传递绑定在特定上下文的对象。
  • 也可以通过给当前AppDomain注册ReflectionOnlyAssemblyResolve事件,手动处理封送阶段的程序集解析逻辑,返回已经加载到反射上下文的对应程序集,但这个方案实现繁琐,没有特殊需求不建议用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:01:14