2014-10-30 54 views
4

我hava小窗口的应用程序,其中用户输入代码和按钮单击事件代码在运行时编译。运行时代码编译给出的错误 - 进程无法访问文件

当我第一次点击按钮时,它工作正常,但如果多次点击同一个按钮,它会给出错误“该进程无法访问Exmaple.pdb文件,因为它正在被另一个进程使用”。。下面的示例代码示例

using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using Microsoft.CSharp; 
using System.CodeDom.Compiler; 
using System.Reflection; 
using System.IO; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 

    var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } }); 
      var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "Example" + ".exe", true); //iloop.ToString() + 
      parameters.GenerateExecutable = true; 
      CompilerResults results = csc.CompileAssemblyFromSource(parameters, 
      @"using System.Linq; 
      class Program { 
       public static void Main(string[] args) {} 

       public static string Main1(int abc) {" + textBox1.Text.ToString() 

        + @" 
       } 
      }"); 
      results.Errors.Cast<CompilerError>().ToList().ForEach(error => Error = error.ErrorText.ToString()); 


var scriptClass = results.CompiledAssembly.GetType("Program"); 
         var scriptMethod1 = scriptClass.GetMethod("Main1", BindingFlags.Static | BindingFlags.Public); 


       StringBuilder st = new StringBuilder(scriptMethod1.Invoke(null, new object[] { 10 }).ToString()); 
       result = Convert.ToBoolean(st.ToString()); 
     } 
    } 
} 

我如何解决这个问题,所以,如果我点击同一个按钮不止一次..它应能正常工作。

感谢,

+1

任何线索..来解决这个问题? – sia 2014-10-30 14:47:47

回答

8
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, 
         "Example" + ".exe", true); 

您明确将输出文件命名为Example.exe。你还会得到Example.pdb,这是为代码生成的调试信息文件,你用第三个参数真实。只要您使用results.CompiledAssembly.GetType(),就会加载生成的程序集,并将Example.exe锁定。由于您已连接调试器,因此调试器将为程序集找到匹配的.pdb文件并加载并锁定它。

在卸载程序集之前,锁将不会被释放。通过标准的.NET Framework规则,这将不会发生,直到您的主appdomain被卸载。通常在程序结束时。

所以试图再次编译代码将会是一条失败的鲸鱼。编译器不能创建.pdb文件,它被调试器锁定。省略true参数不会帮助,它现在将无法创建输出文件Example.exe。

当然你需要解决这个问题。到目前为止,最简单的解决方案是而不是命名输出组件。默认行为是CSharpCodeProvider使用唯一的随机名称生成程序集,您将始终以这种方式避免冲突。更高级的方法是创建一个辅助AppDomain来加载程序集,现在允许在重新编译之前再次卸载它。

去了简单的解决方案:

var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }); 
    parameters.IncludeDebugInformation = true; 
    parameters.GenerateExecutable = true; 
    // etc.. 
+0

让我试试..以上解决方案。 – sia 2014-11-02 13:38:49

+0

谢谢..它正在工作.. – sia 2014-11-03 05:06:13

+0

sia - 你会奖励Hans Passant的奖金吗? – PhillipH 2014-11-08 13:33:35

2

看起来你是在每次按下按钮上,这样就产生了Examples.pdb文件的调试信息每次编译时编译Example.exe,与调试设置。

问题可能是第一次编译过程没有释放它对Examples.pdb的锁定,或者当您运行Example.exe时,Visual Studio正在使用Examples.pdb,因此您无法重新编译它。

这些是我要检查的两件事。