2010-12-07 8 views
20

J'ai passé du temps à jouer avec Clojure-CLR. Mon REPL fonctionne, je peux appeler des classes .NET à partir de Clojure, mais je n'ai pas été capable de comprendre l'appel de DLL Clojure compilées à partir de classes C#.Appeler Clojure à partir de .NET

J'ai essayé d'adapter l'exemple java trouvé here:

J'ai enlevé la: ligne du nom du haut de l'exemple, car il provoque une « clé en double: nom: » erreur. Sans la ligne ": name", le code se compile bien et je peux ajouter la référence dans Visual Studio, mais je n'arrive pas à comprendre comment utiliser le code. J'ai essayé une variété de 'using' des déclarations, mais jusqu'ici rien n'a fonctionné. Quelqu'un peut-il donner un petit aperçu à ce sujet? Voici le code Clojure que j'essaie d'utiliser.

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

Répondre

15

j'ai pu faire fonctionner la manière suivante:

D'abord, je changé votre code un peu, j'avais des problèmes avec l'espace de noms et le compilateur penser les points étaient répertoires. Donc je me suis retrouvé avec ça.

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

Ensuite, je compilé en appelant:

Clojure.Compile.exe hello

Cela crée plusieurs fichiers: hello.clj.dll, hello.clj.pdb, hello.exe et hello.pdb Vous pouvez exécutez hello.exe et il devrait exécuter la fonction -main.

Ensuite, j'ai créé une simple application console C#. J'ai ensuite ajouté les références suivantes: Clojure.dll, hello.clj.dll et hello.exe

Voici le code de l'application de la console:

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

Comme vous pouvez le voir, vous devriez être en mesure pour créer et utiliser la classe hello, il réside dans l'assembly hello.exe. Je ne suis pas pourquoi la fonction "sortie" n'est pas statique, je suppose que c'est un bug dans le compilateur CLR. J'ai également dû utiliser la version 1.2.0 de ClojureCLR comme étant la dernière version de l'assemblage à lancer des exceptions non trouvées.

Pour exécuter l'application, veillez à définir la variable d'environnement clojure.load.path à l'emplacement de vos binaires Clojure.

Espérons que cela aide.

12

Je dirais que vous devriez prendre un autre virage à ce sujet. Tout ce truc de classe gen existe seulement dans clojure comme un hack pour dire au compilateur comment générer des classes wrapper Java/C# autour des variables natives clojure reflective-dynamic.

Je pense qu'il vaut mieux faire tout le "class" en C# et garder votre code clojure plus natif. Votre choix.Mais si vous voulez aller de cette façon, écrire un wrapper comme ceci:

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

De cette façon, votre C# peut ressembler à la normale C#

 
using System; 

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

Et le Clojure peut ressembler à clojure normal:

(ns code.clojure.example.hello) 

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

Cela fonctionnera que vous le compiliez ou que vous le laissiez simplement en tant que script. (RT.load ("bonjour") chargera le script hello.clj s'il existe, sinon il chargera l'assembly hello.clj.dll). Ceci permet à votre clojure de ressembler à du clojure et votre C# à un C#. De plus, il élimine le bogue du compilateur d'interopérabilité clojure de méthode statique (et tout autre bogue d'interopérabilité qui peut exister), puisque vous contournez complètement le compilateur interop clojure.

+0

+1. J'aime cette approche et suis d'accord avec votre raisonnement. En outre, quelque chose ne va pas à propos de la liaison à un fichier EXE. – harpo

Questions connexes