2014-10-30 5 views
4

사용자가 코드를 입력하고 버튼 클릭 이벤트 코드가 런타임에 컴파일되는 작은 창 응용 프로그램을 사용합니다.런타임 코드 컴파일 오류가 발생합니다 - 프로세스가 파일에 액세스 할 수 없습니다

첫 번째 단추를 클릭하면 제대로 작동하지만 두 번 이상 같은 단추를 클릭하면 오류가 발생합니다 "다른 프로세스에서이 프로세스를 사용 중이기 때문에 프로세스가 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()); 
     } 
    } 
} 

이 문제를 해결하면 동일한 버튼을 두 번 이상 누르면 제대로 작동합니다.

감사,

당신이 컴파일 때마다 디버그 정보가 포함 된 Examples.pdb 파일을 생성하도록 디버그 설정으로, 각 버튼 프레스에 Example.exe를 컴파일하는 것 같습니다
+1

단서 .. 이러한 문제를 해결하기 위하여 ?? – sia

답변

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 파일을 만들 수 없으며 디버거에 의해 잠겨 있습니다. 사실 인수를 생략하면 도움을주지 못하며, 이제는 Example.exe 출력 파일을 만들지 못합니다.

당연히 다르게 처리해야합니다. 지금까지 가장 간단한 해결책은 이 아니며 출력 어셈블리 이름입니다. 기본 동작은 CSharpCodeProvider가 고유 한 무작위 이름으로 어셈블리를 생성하기 때문에 항상 그런 식으로 충돌을 피할 수 있습니다. 보다 고급 방법은 보조 AppDomain을 만들어 어셈블리를로드하고 다시 컴파일하기 전에 다시로드 할 수있게하는 것입니다.

간단한 솔루션 간다 :

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

제가 해답을 드리겠습니다. – sia

+0

감사합니다 .. 일하고 있습니다 .. – sia

+0

sia - Hans Passant에게 보너스를 수여 하시겠습니까? – PhillipH

2

.

문제는 첫 번째 컴파일 프로세스가 Examples.pdb에 대한 잠금을 해제하지 않았거나 Example.exe를 실행할 때 Visual Studio에서 Examples.pdb를 사용하고 있으므로 다시 컴파일 할 수없는 것일 수 있습니다.

다음 두 가지 사항을 확인합니다.