CodeDOM -- 执行编译的代码,第二次产生错误
我目前正在努力使用 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 );
}
只有退出程序才能删除可执行文件,就好像该文件被当前应用程序域锁定一样。做什么?谢谢你的帮助!
更新
当上面的代码执行时,主文件被加载到正在执行的程序集中(或者我错了?),调试控制台会显示以下信息:
[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
是我编译代码的主应用程序的名称,该文件不应该加载到其他地方吗? XXX.vshost.exe
打开句柄并且不打开它。卸载AppDomain后不关闭它吗?
i'm currently struggeling with the CodeDOM code generator and executing compiled assemblies.
Everything works like a charm, except running the compiled code a second time.
Settings
The user "programs" a model which will be translated into a executable program. The user can define whether the assembly should created in memory only or on disc, whether to have source code or only an executable. When he clicks the "run" button, the CodeDOM tree is put together and compiled, written out to disc (if needed) and executed.
Exception
When he clicks the "run" button a second time, an exception is thrown:
error CS0016: Unable to write to output file '': --
"The process cannot access the file because it is being used by
another process."
As I can compile the code as often as I want without encountering the error, I would suggest it has something to do how I run the assembly. I searched the web for information on this topic, but all I came up was creating a separate AppDomain
and unloading it afterwards.
Here is the snippet which executes the assembly:
if ( RunProject )
{
_log.info( "Compiled without errors, running..." );
Assembly compiledAssembly = res.CompiledAssembly;
AppDomain compiledAssemblyDomain = AppDomain.CreateDomain( "compiledAssemblyDomain" );
compiledAssemblyDomain.ExecuteAssemblyByName( compiledAssembly.GetName( ) );
AppDomain.Unload( compiledAssemblyDomain );
}
The executable file can only be removed if I quit the program, as if the file is locked by the current appdomain. What to do? Thanks for your help!
Update
When the above code executes, the main file is loaded into the executing assembly (or am I wrong?). The debugging console caputes the following information:
[13:42:19.5576171] i Compiled without errors, running...
'XXX.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\...\bin\main.exe'
and just a few seconds after quitting the executed assembly:
The thread '.NET SystemEvents' (0x20d0) has exited with code 0 (0x0).
The thread '<No Name>' (0x1d20) has exited with code 0 (0x0).
where XXX
is the name of my main application compiling the code. Shouldn't the file loaded somewhere else? Doesn't XXX.vshost.exe
open a handle and don't close it after unloading the AppDomain?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我已经为此苦苦挣扎了很多(我对 Scrolling Game Development Kit 2 做了类似的事情)。您必须非常小心,以确保您对该编译代码执行的所有操作都发生在另一个 AppDomain 内,以便当您卸载该 AppDomain 时,对 DLL 的所有引用都会随之卸载。如果您引用编译代码中的类型,该 DLL 也会被加载到您的 AppDomain 中,并且卸载其他域不会有任何好处。因此,我必须做的是在一个通用 DLL 中定义接口,该 DLL 可以加载到两个域中,以便我可以调用另一个 DLL 中的函数,而无需从另一个 DLL 加载类型。只需确保在其他 DLL 中实例化的每个对象都使用共享 DLL 中定义的接口(或用户定义 DLL 中未定义的另一个公共接口)。然后将您实例化的每个对象从该 DLL 转换为这些接口之一。您永远不能直接使用该 DLL 中定义的类型。
编辑:请注意以下注释:有关 CompiledAssembly 属性的 MSDN 文档
I have wrestled with this quite a bit (I did something similar with Scrolling Game Development Kit 2). You have to be very carefully to make sure that everything you do with that compiled code happens within that other AppDomain so that when you unload that AppDomain, all references to the DLL are unloaded with it. If you so much as refer to a type from the compiled code, that DLL will get loaded into your AppDomain as well and unloading the other domain will do no good. So what I have had to do was define interfaces in a common DLL which can get loaded into both domains so that I can call functions in the other DLL without loading types from the other DLL. Just make sure that every object you instantiate in the other DLL uses an interface defined in the shared DLL (or another public interface not defined in the user-defined DLL). Then cast each object you instantiate from that DLL to one of those interfaces. You can never use the types defined in that DLL directly.
EDIT: Observe the following note from MSDN documentation about the CompiledAssembly Property