c# - Mono 编译器即服务 (MCS)

标签 c# .net 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(' ');
    }

这会在 Evaluator.Run(第一行)处抛出异常:

Illegal enum value: 2049.
Parameter name: access

我相信这是因为 dll 是使用 Mono.exe 而不是 csc.exe 编译的。

我试过直接从 http://tirania.org/blog/archive/2010/Apr-27.html 下载 Mono.CSharp dll在 demo-repl.zip 文件中......并且不会引发异常......但是调用 Evaluator.Evaluate 后的输出参数(res)为空......所以我不确定出了什么问题。没有抛出异常...

所以,我想弄清楚为什么我从 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 的形式处理过)。有谁知道这会有多困难,或者谁能给我指明正确的方向?

谢谢。

最佳答案

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

要解决程序集加载问题,我可以在 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 中,我添加了属性:

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

然后...确保在 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 ();

关于c# - Mono 编译器即服务 (MCS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3407318/

相关文章:

C# 如何在 WCF 应用程序的业务逻辑类中的两个方法之间实现标志消息传递系统?

具有硬编码 getter 和 setter 的 C# 属性

c# - 通用类型层次结构的流畅接口(interface)

java - 静态内部类需要导入注解

c# - 为什么 MailAddress 不拒绝电子邮件地址 someName@gmail?

c# - F# NativePtr.stackalloc 比 C# stackalloc 慢 - 包含反编译代码

c# - PrincipalContext.ValidateCredentials 在 XP 上始终使用 Machine ContextType 返回 False

c++ - 如何为资源编译器设置输出文件夹

compiler-construction - 如何在编译器插件中修改 crate 的所有项目?

c# - 使用 C# 的 XML 注释 cref 属性和参数语法