【问题标题】:CodeDOM -- Execute compiled code, second time yields errorCodeDOM -- 执行编译后的代码,第二次产生错误
【发布时间】:2011-12-08 22:34:26
【问题描述】:

我目前正在努力使用 CodeDOM 代码生成器并执行已编译的程序集。 一切都像一个魅力,除了第二次运行编译的代码。

设置

用户“编程”一个模型,该模型将被翻译成可执行程序。用户可以定义程序集是仅在内存中创建还是在磁盘上创建,是否具有源代码或只有可执行文件。当他单击“运行”按钮时,CodeDOM 树被组合并编译,写入磁盘(如果需要)并执行。

例外

当他第二次点击“运行”按钮时,抛出异常:

错误 CS0016: 无法写入输出文件 '': -- “该进程无法访问该文件,因为它正被 另一个进程。”

由于我可以根据需要随时编译代码而不会遇到错误,因此我建议它与我运行程序集的方式有关。我在网上搜索了有关此主题的信息,但我想出的只是创建一个单独的 AppDomain 并在之后卸载它。

这是执行程序集的 sn-p:

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 是我编译代码的主应用程序的名称。文件不应该加载到其他地方吗? XXX.vshost.exe不是打开一个句柄,卸载AppDomain后不关闭吗?

【问题讨论】:

    标签: c# code-generation appdomain codedom


    【解决方案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 之前,无法删除已编译的程序集。

    【讨论】:

    • 由于我没有对编译后的代码做任何事情而是执行它,所以一切都应该发生在上面声明的 AppDomain 中。如果RunProject 为假,则一切正常。我错过了什么吗?我不是指任何类型的编译代码,只有ExecuteAssemblyByName 提到它。
    • 我担心这可能与您检索程序集名称的方式有关。您是否尝试过将程序集名称硬编码为测试并消除对已编译程序集的“程序集”类型引用?这可以被认为是对您自己域中的程序集的引用。
    • 是的,这就是问题所在(或者更确切地说,填充变量值的 CompiledAssembly 属性的调用是问题所在)。请参阅我编辑的答案。
    • 谢谢,这就是问题所在。但是,如果我对名称进行硬编码,则不会加载已编译的程序集,因此无法找到。使用compiledAssemblyDomain.Load(new AssemblyName("main, ...")) 我只得到一个文件或程序集未找到异常...
    • 您是否尝试过使用 PathToAssembly 属性而不是 CompiledAssembly 属性?也许您可以将它与 LoadFrom 一起使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-03
    • 2010-11-24
    • 1970-01-01
    • 2012-05-25
    • 1970-01-01
    相关资源
    最近更新 更多