单编译器即服务(MCS)编译器、MCS

2023-09-02 10:26:42 作者:雨潇潇

我想消耗Mono的编译器从我的正常.NET 3.5应用程序的服务。

I'd like to consume Mono's compiler as a service from my regular .NET 3.5 application.

我已经下载了最新的比特(2.6.7),创造了在Visual Studio中一个简单的控制台应用程序,并参考了Mono.CSharp DLL。

I've downloaded the latest bits (2.6.7), created a simple console application in Visual Studio and referenced the Mono.CSharp dll.

于是,在我的控制台应用程序(直出样品在线):

Then, in my console app (straight out of a sample online):

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

This throws an exception at Evaluator.Run (the first line):

Illegal enum value: 2049.
Parameter name: access

这是因为DLL是用Mono.exe,不csc.exe的编译,我相信。

This is because the dll was compiled using Mono.exe, not csc.exe, I believe.

我已经试过下载Mono.CSharp DLL直接从的http:// tirania.org/blog/archive/2010/Apr-27.html 在demo-repl.zip文件...并调用计算器后,它不会抛出异常。不过out参数(RES) .Evaluate为空...所以我不知道发生了什么错。没有异常被抛出...

I've tried downloading the Mono.CSharp dll directly from http://tirania.org/blog/archive/2010/Apr-27.html in the demo-repl.zip file...and that does not throw an exception...However the out parameter (res) after calling Evaluator.Evaluate is null...so I'm not sure what's going wrong. No exception is thrown...

所以,我想弄清楚,为什么我从demo-repl.zip下载DLL返回null。

So, I'd like to figure out why the dll I downloaded from the demo-repl.zip returns null.

编辑:我想通了,为什么它返回null。这似乎是出于某种原因编译器不拿起System.Linq命名空间...虽然我不知道为什么。如果我只是评估System.IO.Directory.GetFiles(C:\ ),它工作正常。

I figured out why it returns null. It seems like for some reason the compiler isn't picking up the System.Linq namespace...though I can't tell why...If I just Evaluate "System.IO.Directory.GetFiles ("C:\")", it works fine.

更新:它肯定看起来像有一些错误的单声道编译拿起引用的系统组件。如果我直接复制他们的CSHARP控制台工具样本:

UPDATE: It definitely seems like there's something wrong with the Mono compiler picking up referenced System assemblies. If I directly copy the sample of their csharp console tool:

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

我得到异常:

I get the exception:

{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向实际上是一个可行的解决方案,我将需要修改的编译器,使得它发出,而不是每评估呼叫发射1装配于一个单一的动态组件,(否则presents一个主要的内存泄漏,这我在的CSHARP codeProvider表格前处理)。有没有人有多么困难,这将是一个想法或任何人都可以点我在正确的方向吗?

Also, in order for the MCS to actually be a feasible solution, I'll need to modify the compiler so that it emits to one single dynamic assembly, instead of emitting one assembly per evaluate call (otherwise it presents a major memory leak, which I've dealt with before in the form of the CSharpCodeProvider). Does anyone have an idea of how difficult this will be or can anyone point me in the right direction here?

感谢。

推荐答案

好吧,我觉得我有一些答案。

Ok, I think I have some answers.

要解决的装配载荷的问题,我可以拨打电话到Assembly.LoadWithPartialName内Mono.CSharp.Driver.LoadAssembly,或做在我的应用程序下面的

To resolve the assembly load problem, I can either place a call to Assembly.LoadWithPartialName inside Mono.CSharp.Driver.LoadAssembly, or do the following in my application

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

要进行单声道重复使用相同的动力总成各评估/编译电话,一切我不得不改变如下(虽然有可能是复杂的,我在这里失踪)......

To make Mono reuse the same dynamic assembly for each Evaluate/Compile call, all I had to change is the following (although there are probably complexities I'm missing here).....

里面Mono.CSharp.Evaluator,我加了属性:

Inside Mono.CSharp.Evaluator, I added the property:

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

然后...确保复位被调用至少一次初始化:

Then...make sure Reset is called at least once in Init:

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

最后,在ParseString,根本就没有复位,除非自动复位是真的......

And finally, in ParseString, simply don't reset unless AutoReset is true...

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