从.NET调用Clojure

21

我一直在尝试使用Clojure-CLR。我的REPL正在工作,我可以从Clojure中调用.NET类,但我无法弄清楚如何从C#类中调用已编译的Clojure dlls。

我一直在尝试适应在这里找到的Java示例:

我从示例的顶部删除了":name"行,因为它会导致"Duplicate key: :name"错误。没有":name"行,代码可以很好地编译,并且我可以在Visual Studio中添加引用,但我似乎无法弄清如何使用该代码。我尝试了各种'using'语句,但目前还没有起作用的。是否有人可以提供一些见解?这是我正在尝试使用的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))
2个回答

17

我通过以下方式使其正常工作:

首先,我对您的代码进行了一些修改,因为我在命名空间上遇到了问题,编译器会认为点是目录。所以我最终得到了这个。

(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程序集中。我不知道为什么"output"函数不是静态的,我认为这是CLR编译器中的一个错误。我还必须使用ClojureCLR 1.2.0版本,因为最新版本会引发程序集未找到的异常。

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

希望这能帮到你。


14

我认为你应该采取另一种方法。在Clojure中,所有的gen-class都只是一种hack,用于告诉编译器如何生成包装Java/C#类以围绕本地Clojure反射动态变量。

我认为最好在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程序集)。这样可以使您的Clojure看起来像Clojure,使您的C#看起来像C#。此外,它消除了静态方法Clojure交互编译器错误(以及可能存在的任何其他交互错误),因为您完全绕过了Clojure交互编译器。

+1。我喜欢这种方法,也同意你的推理。而且链接到一个EXE文件感觉有些不对劲。 - harpo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接