Mono 编译器即服务 (MCS)

发布于 2024-09-12 16:20:03 字数 1754 浏览 8 评论 0原文

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

我已经下载了最新版本 (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 下载 Mono.CSharp dll。 demo-repl.zip 文件中的 org/blog/archive/2010/Apr-27.html...并且不会引发异常...但是调用 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 的形式处理过)。有谁知道这有多困难,或者有人可以在这里指出正确的方向吗?

谢谢。

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

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(' ');
    }

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

Illegal enum value: 2049.
Parameter name: access

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

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...

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

EDIT: 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.

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?

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?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白云不回头 2024-09-19 16:20:04

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

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

According to Miguel's blog page you linked, you have to add a reference to System.Core in order to use LINQ on .Net.

csharp> using System.Linq;
csharp> from x in "Foo" select x;
虚拟世界 2024-09-19 16:20:03

好吧,我想我已经有了一些答案。

要解决程序集加载问题,我可以在 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 为 true,否则不要重置......

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

Ok, I think I have some answers.

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).....

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

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 ();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文