2010-08-04 5 views
8

일반 .NET 3.5 응용 프로그램에서 Mono의 컴파일러를 서비스로 사용하고 싶습니다.Mono Compiler as a Service (MCS)

저는 최신 비트 (2.6.7)를 다운로드하고 Visual Studio에서 간단한 콘솔 응용 프로그램을 만들고 Mono.CSharp dll을 참조했습니다.

그런 다음 내 콘솔 응용 프로그램에서 (직선 온라인 샘플 중) :

Illegal enum value: 2049. 
Parameter name: access 

이 있기 때문입니다 :

Evaluator.Run("using System; using System.Linq;"); 
    bool ress; 
    object res; 
    Evaluator.Evaluate(
     "from x in System.IO.Directory.GetFiles (\"C:\\\") select x;", 
     out res, out ress); 

    foreach (var v in (IEnumerable)res) 
    { 
     Console.Write(v); 
     Console.Write(' '); 
    } 

이것은 Evaluator.Run에서 예외 (첫 번째 줄)를 던졌습니다 dll은 csc.exe가 아니라 Mono.exe를 사용하여 컴파일되었습니다.

demo-repl.zip 파일에있는 http://tirania.org/blog/archive/2010/Apr-27.html에서 Mono.CSharp dll을 직접 다운로드하려고했는데 예외가 발생하지 않습니다 ... 그러나 Evaluator.Evaluate를 호출 한 후 out 매개 변수 (res) null 이니 ... 무슨 일이 벌어 질지 모르겠습니다. 예외가 발생하지 않습니다 ...

그래서 demo-repl.zip에서 다운로드 한 dll이 null을 반환하는 이유를 알고 싶습니다.

편집 : 왜 null을 반환하는지 알아 냈습니다. 컴파일러가 System.Linq 네임 스페이스를 선택하지 않은 것처럼 보이지만 이유를 말할 수는 없지만 ... "System.IO.Directory.GetFiles (\"C : \\ " ")", 잘 작동합니다.

업데이트 : 참조 된 시스템 어셈블리를 픽업하는 Mono 컴파일러에 문제가있는 것처럼 보입니다. 내가 직접 CSHARP 콘솔 도구의 샘플을 복사하는 경우 :

csharp> var list = new int [] {1,2,3}; 
csharp> var b = from x in list 
    > where x > 1 
    > select x; 
csharp> b; 

을 나는 예외를 얻을 : MCS를 실제로 실현 가능한 해결책이 될하기 위해,

{interactive}(1,25): error CS1935: An implementation of `Select' query expressio 
n pattern could not be found. Are you missing `System.Linq' using directive or ` 
System.Core.dll' assembly reference? 

도를, 내가해야 평가 호출마다 하나의 어셈블리를 내보내는 대신 하나의 동적 어셈블리로 내보내도록 컴파일러를 수정하십시오. 그렇지 않으면 이전에 CSharpCodeProvider 형식으로 처리 한 주요 메모리 누수가 나타납니다. 누구나 이것이 얼마나 어려울 지에 대한 아이디어를 갖고 있습니까? 아니면 누군가가 저에게 올바른 방향으로 나를 가르 칠 수 있습니까?

감사합니다.

+0

왜 사용하지 않습니까? http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider(VS.80).aspx? – Andrey

+1

CSharpCodeProvider는 컴파일시 어셈블리를 내보내고로드합니다 (메모리 내 옵션 만 사용하는 경우에도 해당). 나는 수천 번의 평가를 수행 할 것이므로 실행중인 AppDomain (메모리 누출)에 수천 개의 어셈블리가로드 될 것입니다. 또한 CSharpCodeProvider는 내부적으로 Reflection.Emit보다 프로세서 집약적 인 csc.exe를 사용합니다. 이전 프로젝트에서는 CSharpCodeProvider를 사용하고 어셈블리 수를 기반으로 재활용 된 별도의 앱 도메인에서 평가를 실행했지만 엄청난 유지 관리 오버 헤드와 매우 오류가 발생하기 쉬운 것으로 입증되어 이러한 접근 방식을 피하고 싶습니다. – Jeff

+0

또한 기본적으로 MCS는 평가 당 하나의 어셈블리를 수행하지만 내부적으로 Reflection.Emit에 의존하기 때문에 AppDomain.DefineDynamicAssembly에 정의 된대로 단일 어셈블리를 내보내는 동작을 변경할 수 있기를 바랍니다. – Jeff

답변

2

좋아, 나는 몇 가지 해답을 가지고 있다고 생각한다.

어셈블리로드 문제를 해결하려면, 나는 모노가 같은 다시 만들려면

 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); 

     private static bool isResolving; 
     static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
     { 
      if (!isResolving) 
      { 
       isResolving = true; 
       var a = Assembly.LoadWithPartialName(args.Name); 
       isResolving = false; 
       return a; 
      } 
      return null; 
     } 

내 응용 프로그램에서 다음 Mono.CSharp.Driver.LoadAssembly 내부 Assembly.LoadWithPartialName, 또는 할 전화를 걸 수 있습니다 동적 어셈블리를 각 Evaluate/Compile 호출에 대해 다음과 같이 변경해야합니다. (여기에는 아마도 복잡함이 있지만 여기에 누락되었습니다.) .....

Inside Mono.CSharp.반드시 리셋이 초기화에 적어도 한 번 호출 될 수 있도록 ... 그런

/// <summary> 
/// Gets or sets a value indicating whether to auto reset when evaluations are performed and create a new assembly. 
/// </summary> 
/// <value><c>true</c> if [auto reset]; otherwise, <c>false</c>.</value> 
public static bool AutoReset { get; set; } 

: 평가자, 나는 속성을 추가

static void Init() 
    { 
     Init (new string [0]); 
     Reset(); 
    } 

을 그리고 마지막으로, parseString을에서, 단순히 자동 리셋이되지 않는 재설정하지 않습니다 사실 ...

 static CSharpParser ParseString (ParseMode mode, string input, out bool partial_input) 
     { 
. 
. 
. 
      if (AutoReset) Reset(); 
+0

그래서, 나는이 같은 문제가 있습니다. 위에서 변경 한 Mono.CSharp.dll의 컴파일 된 버전이 있습니까? 응용 프로그램에서 이것을 사용하고 싶지만 매우 불안정합니다. –

+0

어떤 문제가 있습니까? 위에서 언급 한 변경을 시도 했습니까? 정말 필요하다면 dll을 제공 할 수 있지만 이러한 변경을 수행하고 dll을 직접 컴파일하는 것이 더 나을 것입니다. – Jeff

+0

또한, 결국, 이러한 변경 작업을 수행 한 후에는 다른 문제가 발생하지 않았습니다. – Jeff

1

링크 된 Miguel의 블로그 페이지에 따르면 .Net에서 LINQ를 사용하려면 System.Core에 대한 참조를 추가해야합니다.

csharp> using System.Linq; 
csharp> from x in "Foo" select x; 
+0

아 ... 알 겠어.하지만 GAC 어셈블리 나 프레임 워크 어셈블리를 bin 디렉터리에 복사하지 않기 때문에 참조를 추가하는 것만으로는 충분하지 않습니다. – Jeff