2012-06-05 3 views
0

저는 C# 코드 줄을 받아들이고이를 주변 코드로 묶어서 어셈블리로 컴파일하는 콘솔 유형을 가지고 있습니다. 그런 다음 해당 어셈블리에서 메서드를 호출하고 결과를 출력하면됩니다.런타임 컴파일이 제거 할 수없는 파일을 생성합니다.

문제는 어셈블리에 이름이 있어야하므로 비공개 클래스에 액세스 할 수 있도록 친구 어셈블리로 설정할 수 있다는 것입니다. 나는 그것을 "콘솔"이라고 명명했다.

예상대로 작동하지만 "console"이라는 파일이 이미 디렉토리에 있고 덮어 쓸 수 없기 때문에 두 번째 스크립트를 실행할 수 없다는 문제가 있습니다.

나는 Dispose 메서드가있는 모든 것을 처리하려고 시도했습니다. File.Delete 수동으로 파일을 삭제하려고했습니다. 아무것도 도움이되지 않았습니다.

그래서 여기에 제가 사용하고있는 코드가 있습니다. 누군가가 나를 도울 수 있기를 바랍니다.

CSharpCodeProvider provider = new CSharpCodeProvider(); 
var param = new CompilerParameters(); 
param.GenerateInMemory = false; 
param.GenerateExecutable = false; 
param.OutputAssembly = "console"; 
param.ReferencedAssemblies.Add("System.dll"); 
param.ReferencedAssemblies.Add("System.Core.dll"); 
param.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location); 
var results = provider.CompileAssemblyFromSource(param, 
@" 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.IO; 

namespace FireflyGL 
{ 
class DebugConsole 
{ 
    static void Run(StringWriter writer) 
    { 
     var stdOut = Console.Out; 
     Console.SetOut(writer); 
     " + input.Text + @" 
     Console.SetOut(stdOut); 
    } 
} 
}"); 
      if (results.Errors.HasErrors) 
      { 
       for (int i = 0; i < results.Errors.Count; ++i) 
       { 
        PushText(results.Errors[i].ErrorText); 
       } 
      } 
      else 
      { 
       try 
       { 
        var writter = new StringWriter(); 
        results.CompiledAssembly.GetType("FireflyGL.DebugConsole").GetMethod("Run", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, new object[] { writter }); 
        PushText(writter.ToString()); 
        history.Add(input.Text); 
        currentHistory = history.Count; 
        input.Text = ""; 
        writter.Dispose(); 
       } 
       catch (Exception) 
       { 

       } 
      } 
      provider.Dispose(); 
      File.Delete(results.CompiledAssembly.Location); 

답변

1

모든 참조를 없애려면 어셈블리를 언로드해야합니다. 불행히도, 당신은 그렇게 할 수 없습니다. 그러나 AppDomain을 언로드 할 수 있으며 해당 어셈블리를 AppDomain에서 참조하면 해당 어셈블리도 언로드됩니다. 응용 프로그램 도메인을 사용 장소를 메모리 누수를 만드는 방법에 대해 걱정하지 않는 경우

, 당신은 또한 당신의 어셈블리에 대한 고유 한 이름을 만들 수 있습니다 (console1, console2 등.) ...

+0

나는 온라인 예를 참조했다 그러나 나는 어떻게 정말로 이해하지 못한다. 어셈블리를 특정 AppDomain에서 참조하도록하려면 어떻게합니까? –

+0

신경 쓰지 마십시오. 내가 대답을 찾았 : http://stackoverflow.com/questions/1799373/how-can-i-prevent-compileassemblyfromsource-from-leaking-memory –

+0

그것에 대해 갈 다른 방법이 있습니까? 나는 놀고 있었고 AppDomain은 나에게 많은 문제를주고있다. 스크립트에 객체 참조를 보낼 수 있어야하지만 이상한 "객체가 직렬화되지 않음"예외가 발생합니다. –

관련 문제