我目前正在使用CodeDOM代码生成器并执行已编译的程序集。 除了第二次运行编译代码外,一切都像魅力一样。
设置
用户“编程”将被翻译成可执行程序的模型。用户可以定义程序集是仅在内存中还是在光盘上创建,无论是源代码还是仅可执行文件。当他点击“运行”按钮时,CodeDOM树被放在一起并编译,写出到光盘(如果需要)并执行。
异常
当他第二次点击“运行”按钮时,会抛出异常:
错误CS0016:无法写入输出文件'': - “进程无法访问该文件,因为它正在被使用 另一个过程。“
由于我可以根据需要经常编译代码而不会遇到错误,我建议我有一些操作方法可以运行程序集。我在网上搜索了有关此主题的信息,但我提出的所有内容都是创建一个单独的AppDomain
并在之后卸载它。
以下是执行程序集的代码段:
if ( RunProject )
{
_log.info( "Compiled without errors, running..." );
Assembly compiledAssembly = res.CompiledAssembly;
AppDomain compiledAssemblyDomain = AppDomain.CreateDomain( "compiledAssemblyDomain" );
compiledAssemblyDomain.ExecuteAssemblyByName( compiledAssembly.GetName( ) );
AppDomain.Unload( compiledAssemblyDomain );
}
只有在我退出程序时才能删除可执行文件,就好像该文件被当前的appdomain锁定一样。该怎么办?谢谢你的帮助!
更新
当上面的代码执行时,主文件被加载到执行程序集中(或者我错了吗?)。调试控制台会输入以下信息:
[13:42:19.5576171] i Compiled without errors, running...
'XXX.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\...\bin\main.exe'
退出已执行的程序集后几秒钟:
The thread '.NET SystemEvents' (0x20d0) has exited with code 0 (0x0).
The thread '<No Name>' (0x1d20) has exited with code 0 (0x0).
其中XXX
是我编译代码的主应用程序的名称。文件不应该加载到其他地方吗?在卸载AppDomain后,XXX.vshost.exe
是否打开句柄并且不关闭它?
答案 0 :(得分:1)
我已经对此进行了相当多的努力(我用Scrolling Game Development Kit 2做了类似的事情)。您必须非常小心地确保使用该编译代码执行的所有操作都发生在该其他AppDomain中,以便在卸载该AppDomain时,所有对DLL的引用都将随之卸载。如果您从编译代码中引用类型,那么该DLL也将被加载到您的 AppDomain中,并且卸载其他域将无济于事。所以我必须要做的是在一个公共DLL中定义接口,这些接口可以加载到两个域中,这样我就可以调用另一个DLL中的函数而无需从其他DLL加载类型。只需确保在另一个DLL中实例化的每个对象都使用共享DLL(或未在用户定义的DLL中定义的另一个公共接口)中定义的接口。然后将您从该DLL实例化的每个对象转换为其中一个接口。您永远不能直接使用该DLL中定义的类型。
编辑:观察MSDN documentation about the CompiledAssembly Property
中的以下注释注意强> CompiledAssembly属性的get访问器调用Load方法来加载 编译汇编到当前的应用程序域。在调用get访问器之后, 在卸载当前AppDomain之前,无法删除已编译的程序集。