20

我一直在玩 Clojure-CLR。我的 REPL 正在工作,我可以从 Clojure 调用 .NET 类,但我无法弄清楚从 C# 类调用已编译的 Clojure dll。

我一直在尝试调整此处找到的 java 示例:

我从示例顶部删除了 :name 行,因为它会导致“Duplicate key: :name”错误。如果没有 ":name" 行,代码编译得很好,我可以在 Visual Studio 中添加引用,但我似乎无法弄清楚如何使用代码。我尝试了各种“使用”语句,但到目前为止没有任何效果。任何人都可以对此提供一些见解吗?这是我尝试使用的 Clojure 代码。

(ns code.clojure.example.hello
  (:gen-class
   :methods [#^{:static true} [output [int int] int]]))

(defn output [a b]
  (+ a b))

(defn -output
  [a b]
  (output a b))
4

2 回答 2

16

我能够让它工作做以下事情:

首先,我稍微更改了您的代码,我在命名空间方面遇到了问题,编译器认为这些点是目录。所以我结束了这个。

(ns hello
  (:require [clojure.core])
  (:gen-class
   :methods [#^{:static true} [output [int int] int]]))

(defn output [a b]
  (+ a b))

(defn -output [a b]
  (output a b))

(defn -main []
  (println (str "(+ 5 10): " (output 5 10))))

接下来我通过调用编译它:

Clojure.Compile.exe hello

这将创建几个文件:hello.clj.dll、hello.clj.pdb、hello.exe 和 hello.pdb 您可以执行 hello.exe,它应该运行 -main 函数。

接下来,我创建了一个简单的 C# 控制台应用程序。然后我添加了以下引用:Clojure.dll、hello.clj.dll 和 hello.exe

这是控制台应用程序的代码:

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            hello h = new hello();
            System.Console.WriteLine(h.output(5, 9));
            System.Console.ReadLine();
        }
    }
}

如您所见,您应该能够创建和使用 hello 类,它位于 hello.exe 程序集中。我不是为什么函数“输出”不是静态的,我认为这是 CLR 编译器中的错误。我还必须使用 ClojureCLR 的 1.2.0 版本,因为最新的版本是抛出未找到的程序集异常。

为了执行应用程序,请确保将 clojure.load.path 环境变量设置为 Clojure 二进制文件所在的位置。

希望这可以帮助。

于 2010-12-09T02:51:18.497 回答
14

我认为你应该对此采取另一种策略。所有这些 gen-class 的东西只存在于 clojure 中,作为一种 hack,告诉编译器如何围绕本机 clojure 反射动态变量生成包装 Java/C# 类。

我认为最好在 C# 中完成所有“类”的工作,并让您的 clojure 代码更加原生。你的选择。但是如果你想这样,写一个这样的包装器:

using System;
using clojure.lang;

namespace ConsoleApplication {
    static class Hello {
        public static int Output(int a, int b) {
            RT.load("hello");
            var output = RT.var("code.clojure.example.hello", "output");
            return Convert.ToInt32(output.invoke(a, b));
        }
    }
}

这样你的 C# 就可以看起来像普通的 C#

using System;

namespace ConsoleApplication {
    class Program {
        static void Main() {
            Console.WriteLine("3+12=" + Hello.Output(3, 12));
            Console.ReadLine();
        }
    }
}

clojure 可以看起来像普通的 clojure:

(ns code.clojure.example.hello)

(defn output [a b]
  (+ a b))

无论您是编译它还是将其保留为脚本,这都将起作用。(RT.load("hello") 将加载脚本 hello.clj 如果它存在,否则它将加载 hello.clj.dll 程序集)。

This allows your clojure to look like clojure and your C# to look like C#. Plus it eliminates the static method clojure interop compiler bug (and any other interop bugs that may exist), since you're completely circumventing the clojure interop compiler.

于 2010-12-30T06:57:20.273 回答