C# 如何将运行时动态编译生成的类对象转换为编译时定义的类实例
问题根因
.NET 运行时判定两个类型是否可以转换,依赖「程序集强名称 + 命名空间 + 类型名称」的三元组身份匹配,不是单纯的成员结构相似就可以兼容。
你单独编译生成的
Tester类位于全新的动态程序集内,哪怕它的命名空间、类名、所有成员和游戏原生加载的Tester完全一致,对CLR来说也是两个毫无关联的独立类型,因此强制转换必然抛出InvalidCastException。受限于你无法修改游戏核心调用逻辑、无法提前抽离公共接口的约束,常规的跨程序集适配方案完全无法适配当前场景。
适配当前限制的可落地方案
核心思路直接跳过「新程序集生成Tester实例再强制转旧类型」的死路——本质上你新建的这个Tester对象从生成的那一刻起就不可能通过类型校验,所有方案都围绕直接操作游戏已加载的原Tester类型的元数据,把新编译的逻辑注入进去,全程不生成独立的新Tester类型设计。
运行时方法补丁注入(最适配游戏Mod开发场景)
- 完全不需要生成独立的Tester类实例,新代码编译时,只编译需要替换的方法逻辑片段,不要生成完整的Tester类定义。
- 编译参数里直接把游戏进程已加载的Tester所在程序集作为唯一引用,让编译器生成的IL代码直接绑定原Tester的方法签名,而不是在新程序集里重复生成新的Tester类型定义。
- 运行时把编译好的方法实现,直接替换到原Tester类型的对应方法槽:
- 原Tester的方法是虚方法时,直接通过反射修改方法的实现指针
- 原方法是非虚、私有静态方法时,直接改写方法体的IL指令流,用新编译的逻辑覆盖原有执行流程,全程不需要改动任何游戏原有代码
- 这种方案下,游戏所有调用逻辑拿到的仍然是原本的Tester类型、原本的实例对象,只是方法执行的逻辑换成了你新编译的版本,完全没有跨程序集类型不兼容的问题。
编译期强制类型转发到已加载程序集
- 编译新代码时,关闭编译器对Tester类型的独立生成逻辑:关联游戏已加载的原程序集的Tester类型引用作为编译期类型来源,同时在编译的源代码里,不要写完整的
public class Tester {}类声明,只编写需要新增的成员逻辑。 - 编译器识别到引用的已加载程序集里已经存在
Test.Tester类型时,就不会在新生成的程序集里重复定义同名类型,所有和Tester相关的代码都会直接指向原程序集里那个已经加载到游戏进程的类型。 - 这种方式下新编译代码里用到的Tester,和游戏代码里的Tester是CLR层面完全一致的同一个类型,自然不存在转换失败的问题。
关键踩坑提示
- 绝对不要在新编译的代码里写和原程序集同名的完整类定义:只要编译器识别到类名和引用的已加载类型同名,就会默认生成新的独立类型,直接堵死后续所有类型适配的路径。
- 如果必须要新建Tester实例,不要在新程序集里直接
new,而是通过反射调用原程序集里Tester类型的构造函数创建实例,这个实例的类型从生成开始就是原程序集的,天然能被游戏的所有调用逻辑识别。
内容的提问来源于stack exchange,提问作者VeryGoodDog
相关产品推荐
相关产品推荐

