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

Jef*_*eff 8 .net c# compiler-construction mono gmcs

我想从我的常规.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(' ');
    }
Run Code Online (Sandbox Code Playgroud)

这会在Evaluator.Run(第一行)引发异常:

Illegal enum value: 2049.
Parameter name: access
Run Code Online (Sandbox Code Playgroud)

这是因为dll是使用Mono.exe编译的,而不是csc.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;
Run Code Online (Sandbox Code Playgroud)

我得到了例外:

{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?
Run Code Online (Sandbox Code Playgroud)

此外,为了使MCS实际上是一个可行的解决方案,我需要修改编译器,使其发送到一个动态程序集,而不是每次评估调用发出一个程序集(否则会出现主要的内存泄漏,我之前以CSharpCodeProvider的形式处理过.有没有人知道这会有多困难,或者有人能指出我在这方面的正确方向吗?

谢谢.

Jef*_*eff 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;
        }
Run Code Online (Sandbox Code Playgroud)

为了使 Mono 为每个评估/编译调用重用相同的动态程序集,我必须更改以下内容(尽管我在这里可能缺少复杂性)......

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

/// <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; }
Run Code Online (Sandbox Code Playgroud)

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

    static void Init ()
    {
        Init (new string [0]);
        Reset();
    }
Run Code Online (Sandbox Code Playgroud)

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

        static CSharpParser ParseString (ParseMode mode, string input, out bool partial_input)
        {
.
.
.
            if (AutoReset) Reset ();
Run Code Online (Sandbox Code Playgroud)