单声道编译器即服务(MCS)

我想从我的常规.NET 3.5应用程序中使用Mono的编译器作为服务。

我已经下载了最新的位(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(第一行)引发exception:

 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 ……这不会引发exception。 ..但是在调用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; 

我得到了例外:

 {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的forms处理过。 有没有人知道这将是多么困难,或者有人能指出我在这里正确的方向?

谢谢。

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

要解决程序集加载问题,我可以在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; } 

为了让Mono为每个Evaluate / Compile调用重用相同的动态程序集,我必须改变的是以下内容(尽管我可能会在这里找到复杂性)…..

在Mono.CSharp.Evaluator中,我添加了属性:

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

然后……确保在Init中至少调用一次Reset:

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

最后,在ParseString中,除非AutoReset为真,否则不要重置…

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

根据您链接的Miguel博客页面,您必须添加对System.Core的引用才能在.Net上使用LINQ。

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