重新编译C#运行时,没有AppDomains [英] Recompile C# while running, without AppDomains

查看:174
本文介绍了重新编译C#运行时,没有AppDomains的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有两个C#应用程序 - game.exe (XNA,需要支持Xbox 360)和 editor.exe (XNA托管在WinForms中) - 它们都共享一个 engine.dll 程序集,完成大部分工作。

Let’s say that I have two C# applications - game.exe (XNA, needs to support Xbox 360) and editor.exe (XNA hosted in WinForms) - they both share an engine.dll assembly that does the vast majority of the work.

现在我们想添加一些基于C#的脚本(它不是很脚本化,但我会称之为)。每个级别都有自己的继承自一个基类的类(我们称之为 LevelController )。

Now let’s say that I want to add some kind of C#-based scripting (it’s not quite "scripting" but I’ll call it that). Each level gets its own class inherited from a base class (we’ll call it LevelController).

这些脚本的重要限制:


  1. 他们需要是真实的编译C#代码

  1. They need to be real, compiled C# code

它们应该需要最少的手动粘合工作(如果有的话)

They should require minimal manual "glue" work, if any

他们必须在同一个AppDomain中运行, / p>

They must run in the same AppDomain as everything else

对于游戏 - 这很简单:所有的脚本类都可以编译成一个程序集code> levels.dll ),并且可以根据需要使用反射来实例化各个类。

For the game - this is pretty straight forward: All the script classes can be compiled into an assembly (say, levels.dll) and the individual classes can be instanced using reflection as needed.

编辑器更难。编辑器具有在编辑器窗口中播放游戏的能力,然后将所有内容重置回它开始的位置(这就是为什么编辑器需要首先了解这些脚本)。

The editor is much harder. The editor has the ability to "play the game" within the editor window, and then reset everything back to where it started (which is why the editor needs to know about these scripts in the first place).

我想要实现的基本上是一个重新加载脚本按钮在编辑器中,将重新编译和加载与正在编辑的级别相关联的脚本类,当用户按下播放按钮,创建最近编译的脚本的实例。

What I am trying to achieve is basically a "reload script" button in the editor that will recompile and load the script class associated with the level being edited and, when the user presses the "play" button, create an instance of the most recently compiled script.

其结果将是编辑器中的快速编辑测试工作流程(而不是替代 - 保存级别,关闭编辑器,重新编译解决方案,启动编辑器,加载级别,测试)。

The upshot of which will be a rapid edit-test workflow within the editor (instead of the alternative - which is to save the level, close the editor, recompile the solution, launch the editor, load the level, test).

我已经制定了一个潜在的方法来实现这一点 - 这本身导致一些问题(如下所示):

Now I think I have worked out a potential way to achieve this - which itself leads to a number of questions (given below):


  1. 编译给定级别(或,如果需要,整个级别)所需的 .cs 文件的集合。 dll project)到一个临时的,唯一命名的程序集。该程序集需要引用 engine.dll 。如何在运行时以这种方式调用编译器?如何让它输出这样的程序集(我可以在内存中做它)?

  1. Compile the collection of .cs files required for a given level (or, if need be, the whole levels.dll project) into a temporary, unique-named assembly. That assembly will need to reference engine.dll. How to invoke the compiler this way at runtime? How to get it to output such an assembly (and can I do it in memory)?

载入新程式集。将重要的是,我加载类同名的类进入同一个过程? (我的印象是,这些名称是由程序集名称限定的)

Load the new assembly. Will it matter that I am loading classes with the same name into the same process? (I am under the impression that the names are qualified by assembly name?)

现在,正如我所提到的,我不能使用AppDomains。但是,另一方面,我不介意泄漏旧版本的脚本类,所以卸载的能力不重要。除非是?我假设加载可能有几百个程序集是可行的。

Now, as I mentioned, I can’t use AppDomains. But, on the other hand, I don’t mind leaking old versions of script classes, so the ability to unload isn’t important. Unless it is? I’m assuming that loading maybe a few hundred assemblies is feasible.

当玩层次时,实例类继承自LevelController,刚刚加载。如何做到这一点?

When playing the level, instance the class that is inherited from LevelController from the specific assembly that was just loaded. How to do this?

最后:

这是一个明智的做法吗?

Is this a sensible approach? Could it be done a better way?

更新:这些天我使用

UPDATE: These days I use a far simpler approach to solve the underlying problem.

推荐答案

检查输出Microsoft.CSharp.CSharpCodeProvider和System.CodeDom.Compiler周围的命名空间。

Check out the namespaces around Microsoft.CSharp.CSharpCodeProvider and System.CodeDom.Compiler.



编译集合。 cs文件

Compile the collection of .cs files


应该很简单,如 http://support.microsoft.com/kb/304655



我在同一个进程中加载​​同名的类是否重要?

Will it matter that I am loading classes with the same name into the same process?


不是。它只是名字。



实例继承自LevelController的类。

instance the class that is inherited from LevelController.


加载您创建的程序集Assembly.Load等。使用反射查询您想要使用的类型。获取构造函数并调用它。

Load the assembly that you created something like Assembly.Load etc. Query the type you want to instanciate using reflection. Get the constructor and call it.

这篇关于重新编译C#运行时,没有AppDomains的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆