假设我有两个 C# 应用程序—— game.exe
(XNA,需要支持 Xbox 360)和editor.exe
(XNA 托管在 WinForms 中)——它们都共享一个engine.dll
程序集来完成大部分工作。
现在假设我想添加某种基于 C# 的脚本(它不完全是“脚本”,但我会这么称呼它)。每个级别都有自己的类继承自一个基类(我们称之为LevelController
)。
这些是这些脚本的重要约束:
它们需要是真实的、经过编译的 C# 代码
他们应该需要最少的手动“胶水”工作,如果有的话
它们必须和其他所有东西在同一个 AppDomain 中运行
对于游戏 - 这非常简单:所有脚本类都可以编译成一个程序集(例如,levels.dll
),并且可以根据需要使用反射来实例化各个类。
编辑器更难。编辑器能够在编辑器窗口中“玩游戏”,然后将所有内容重置回它开始的位置(这就是为什么编辑器首先需要了解这些脚本的原因)。
我想要实现的基本上是编辑器中的“重新加载脚本”按钮,它将重新编译和加载与正在编辑的关卡关联的脚本类,当用户按下“播放”按钮时,创建一个最近的实例编译好的脚本。
其结果将是编辑器内的快速编辑测试工作流程(而不是替代方案 - 保存关卡、关闭编辑器、重新编译解决方案、启动编辑器、加载关卡、测试)。
现在我想我已经找到了一种可能的方法来实现这一点——这本身就会导致一些问题(如下所示):
.cs
将给定级别(或者,如果需要,整个项目)所需的文件集合编译levels.dll
成一个临时的、唯一命名的程序集。该程序集将需要引用engine.dll
. 如何在运行时以这种方式调用编译器?如何让它输出这样的程序集(我可以在内存中完成)?加载新程序集。将具有相同名称的类加载到同一进程中是否重要?(我的印象是名称由程序集名称限定?)
现在,正如我所提到的,我不能使用 AppDomains。但是,另一方面,我不介意泄露旧版本的脚本类,因此卸载能力并不重要。除非是?我假设加载可能几百个程序集是可行的。
播放关卡时,实例化从刚刚加载的特定程序集继承自 LevelController 的类。这该怎么做?
最后:
这是一个明智的做法吗?可以做得更好吗?
更新:这些天我使用一种更简单的方法来解决根本问题。