2010-08-04 93 views
8

我想從我的常規.NET 3.5應用程序中使用Mono的編譯器作爲服務。單聲道編譯器即服務(MCS)

我已經下載了最新的位(2.6.7),在Visual Studio中創建了一個簡單的控制檯應用程序,並引用了Mono.CSharp dll。

然後,在我的控制檯應用程序(直出樣品在線):

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異常(第一行):

Illegal enum value: 2049. 
Parameter name: access 

這是因爲我相信dll是使用Mono.exe編譯的,而不是csc.exe。

我試過在demo-repl.zip文件中直接從http://tirania.org/blog/archive/2010/Apr-27.html下載Mono.CSharp dll ...並且不會引發異常......但是調用Evaluator.Evaluate之後的out參數(res)是空的...所以我不知道發生了什麼問題。沒有例外拋出...

所以,我想弄清楚爲什麼我從demo-repl.zip下載的DLL返回null。

編輯:我想通了它爲什麼返回null。這似乎是由於某種原因編譯器沒有拿起System.Linq命名空間......雖然我不能說出爲什麼......如果我只是評估「System.IO.Directory.GetFiles(\」C:\\ 「)」,它工作正常。

更新:它看起來像是單引擎編譯器拾取引用的系統程序集有問題。如果我直接在其CSHARP控制檯工具的樣本複製:

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

我得到異常:

{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? 

此外,爲了使MCS實際上是一個可行的解決方案,我需要修改編譯器,以便它發出一個動態程序集,而不是每次評估調用都發出一個程序集(否則會出現一個主要的內存泄漏,我之前已經用CSharpCodeProvider的形式處理過)。有沒有人知道這將是多麼困難,或者有誰能夠指出我在這個正確的方向?

謝謝。

+0

爲什麼不使用http://msdn.microsoft.com/en-us/library/microsoftoft.csharp.csharpcodeprovider(VS.80).aspx? – Andrey 2010-08-04 15:53:07

+1

CSharpCodeProvider每次編譯都會發出並加載程序集(即使只使用內存中的選項)。我將執行數千次評估,因此會有數千個程序集加載到正在執行的AppDomain中(內存泄漏)。此外,CSharpCodeProvider內部使用csc.exe,這比Reflection.Emit處理器密集得多。在之前的項目中,我使用了CSharpCodeProvider,並在根據程序集數量回收的單獨應用程序域中運行評估,但事實證明這是一個巨大的維護開銷,並且非常容易出錯,所以我想避免這種方法。 – Jeff 2010-08-04 16:03:40

+0

另外,我意識到,默認情況下,MCS在每次評估時也會執行一個程序集,但是由於它在內部依賴於Reflection.Emit,我希望能夠更改該行爲以發送到由AppDomain.DefineDynamicAssembly定義的單個程序集。 – Jeff 2010-08-04 16:05:53

回答

2

好吧,我想我有一些答案。

要解決組裝負荷的問題,我可以撥打電話裏面Mono.CSharp.Driver.LoadAssembly Assembly.LoadWithPartialName,或做在我的應用

 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; 
     } 

爲了使單重用同一以下動態彙編每個評估/編譯調用,所有我不得不改變以下(雖然可能有複雜性,我在這裏失蹤).....

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,其中包含上述更改?我想在應用程序中使用它,但我發現它非常不穩定。 – 2010-09-13 15:09:40

+0

你有什麼問題?你有沒有嘗試過上面提到的改變?如果你真的需要它,我可以提供一個dll,但是你可能更好的做出這些更改並自己編譯dll。 – Jeff 2010-09-13 16:56:18

+0

另外,在我的最後,在做出這些改變之後,我還沒有真的遇到過其他問題......是嗎? – Jeff 2010-09-13 18:01:53

1

根據您鏈接的Miguel的博客頁面,您必須添加對System.Core的引用才能在.Net上使用LINQ。

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

啊......我明白了,但添加引用是不夠的,因爲它不會將GAC程序集或框架程序集複製到bin目錄。 – Jeff 2010-08-04 21:25:54