2010-12-07 21 views
20

Ich habe einige Zeit damit verbracht, mit Clojure-CLR zu spielen. Meine REPL funktioniert, ich kann .NET-Klassen von Clojure aufrufen, aber ich konnte keine kompilierten Clojure-DLLs aus C# -Klassen aufrufen.Aufruf von Clojure von .NET

Ich habe versucht, das Java-Beispiel anzupassen gefunden here:

Ich entfernte die: Name Zeile von oben aus dem Beispiel, weil sie einen „Duplicate Schlüssel: Name“ verursachen Fehler. Ohne die Zeile ": name" wird der Code korrekt kompiliert und ich kann den Verweis in Visual Studio hinzufügen, aber ich kann nicht herausfinden, wie der Code verwendet wird. Ich habe eine Vielzahl von 'using'-Anweisungen ausprobiert, aber bisher hat noch nichts funktioniert. Kann jemand dazu einen kleinen Einblick geben? Hier ist der Clojure-Code, den ich versuche zu verwenden.

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

Antwort

15

Ich war in der Lage, es zu bekommen folgendes zu arbeiten tun:

Zuerst habe ich Ihren Code ein wenig verändert, ich habe Probleme mit dem Namespace und dem Compiler die Punkte waren Verzeichnisse zu denken haben. Also endete ich damit.

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

Next ich es kompiliert durch den Aufruf:

Clojure.Compile.exe hello

Dies schafft mehrere Dateien: hello.clj.dll, hello.clj.pdb, hello.exe und hello.pdb Sie können Führe hallo.exe aus und es sollte die -main-Funktion ausführen.

Als nächstes habe ich eine einfache C# -Konsolenanwendung erstellt. Ich habe dann die folgenden Hinweise: Clojure.dll, hello.clj.dll und hello.exe

Hier ist der Code der Konsolenanwendung ist:

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

Wie Sie sehen können, sollten Sie in der Lage sein, Um die Hallo-Klasse zu erstellen und zu verwenden, befindet sie sich in der Assembly hello.exe. Ich bin nicht, warum die Funktion "output" nicht statisch ist, ich nehme an, es ist ein Fehler im CLR-Compiler. Ich musste auch die 1.2.0-Version von ClojureCLR verwenden, da die letzten Ausnahmen nicht gefunden wurden.

Um die Anwendung auszuführen, stellen Sie sicher, dass die Umgebungsvariable clojure.load.path auf die Position Ihrer Clojure-Binärdateien gesetzt ist.

Hoffe, das hilft.

12

Ich würde argumentieren, dass Sie eine andere Wende auf diesem nehmen sollten. All diese Gen-Klassen-Sachen gibt es nur in clojure als Hack, um dem Compiler zu sagen, wie Wrapper-Java/C# -Klassen um die nativen clojure reflective-dynamischen Variablen generiert werden.

Ich denke, es ist besser, alle "Klassen" Zeug in C# zu tun und halten Sie Ihren clojure Code nativer. Deine Entscheidung.Aber wenn man diesen Weg gehen möchten, schreiben Sie eine Wrapper wie folgt aus:

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

Auf diese Weise C# wie normale C# aussehen kann

 
using System; 

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

Und die clojure können wie normale clojure aussehen:

(ns code.clojure.example.hello) 

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

Dies funktioniert, ob Sie es kompilieren oder einfach als Skript lassen. (RT.load ("Hallo") lädt das Skript hello.clj, falls es existiert, oder sonst lädt es die hello.clj.dll-Assembly).

Dadurch kann Ihr clojure wie clojure aussehen und Ihre C# wie C# aussehen. Außerdem beseitigt es die statische Methode clojure interop compiler bug (und alle anderen Interop-Bugs, die möglicherweise existieren), da Sie den clojure interop Compiler vollständig umgehen.

+0

+1. Ich mag diesen Ansatz und stimme Ihrer Argumentation zu. Auch etwas fühlt sich falsch an, wenn man mit einer EXE verlinkt. – harpo