2010-08-04 24 views
8

Ich möchte Monos Compiler als einen Dienst von meiner regulären .NET 3.5-Anwendung verbrauchen.Mono-Compiler als Dienst (MCS)

Ich habe die neuesten Bits (2.6.7) heruntergeladen, erstellt eine einfache Konsolenanwendung in Visual Studio und referenzierte die Mono.CSharp dll.

Dann in meiner Konsolenanwendung (gerade jetzt online einer Probe):

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

Dies löst eine Ausnahme bei Evaluator.Run (die erste Zeile):

Illegal enum value: 2049. 
Parameter name: access 

Dies liegt daran, Die DLL wurde mit Mono.exe und nicht mit csc.exe kompiliert, glaube ich.

Ich habe versucht, die Mono.CSharp dll direkt von http://tirania.org/blog/archive/2010/Apr-27.html in der Datei demo-repl.zip ... und das wirft keine Ausnahme ... Allerdings die out-Parameter (res) nach dem Aufruf von Evaluator.Evaluate ist null ... also bin ich mir nicht sicher, was schief läuft. Es wird keine Ausnahme geworfen ...

Also, ich würde gerne herausfinden, warum die DLL, die ich von der demo-repl.zip heruntergeladen habe, Null zurückgibt.

EDIT: Ich habe herausgefunden, warum es Null zurückgibt. Aus irgendeinem Grund scheint der Compiler den System.Linq-Namespace nicht aufzunehmen ... obwohl ich nicht sagen kann, warum ... Wenn ich nur "System.IO.Directory.GetFiles (\" C: \\ ")", es funktioniert gut.

UPDATE: Es scheint auf jeden Fall etwas falsch mit dem Mono-Compiler zu sein, der referenzierte System-Assemblies abruft. Wenn ich direkt auf die Probe ihres csharp Konsolen-Tool kopieren:

csharp> var list = new int [] {1,2,3}; 
csharp> var b = from x in list 
    > where x > 1 
    > select x; 
csharp> b; 

ich die Ausnahme erhalten:

{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? 

auch in Ordnung, für den MCS, um tatsächlich eine realisierbare Lösung zu sein, ich werde müssen Ändern Sie den Compiler so, dass er an eine einzige dynamische Assembly gesendet wird, anstatt eine Assembly pro Evaluierungsaufruf auszugeben (andernfalls wird ein größerer Speicherverlust angezeigt, den ich zuvor in Form des CSharpCodeProviders behandelt habe). Hat jemand eine Vorstellung davon, wie schwer das sein wird oder kann mir hier jemand in die richtige Richtung zeigen?

Danke.

+0

warum nicht http://msdn.microsoft.com/en-us/library/microsoft.csharp.csharpcodeprovider(VS.80).aspx zu benutzen? – Andrey

+1

CSharpCodeProvider sendet und lädt eine Assembly pro Kompilierung (auch wenn Sie die Option Nur im Arbeitsspeicher verwenden). Ich werde Tausende von Auswertungen durchführen und somit Tausende von Assemblys in die ausführende AppDomain laden (Speicherleck). Außerdem verwendet CSharpCodeProvider intern csc.exe, das weitaus rechenintensiver als Reflection.Emit ist. In einem früheren Projekt habe ich CSharpCodeProvider verwendet und Evaluierungen in einer separaten Anwendungsdomäne ausgeführt, die basierend auf der Assembly-Anzahl wiederverwendet wurde. Dies erwies sich jedoch als enormer Wartungsaufwand und sehr fehleranfällig. Daher möchte ich diesen Ansatz vermeiden. – Jeff

+0

Auch, ich weiß, dass standardmäßig MCS auch eine einzelne Assembly pro evaluieren, aber da es auf Reflection.Emit intern beruht, hoffe ich, dass ich dieses Verhalten auf eine einzelne Assembly emittieren können, wie von AppDomain.DefineDynamicAssembly definiert. – Jeff

Antwort

2

Ok, ich denke, ich habe ein paar Antworten.

die Montagelast Problem zu beheben, kann ich entweder einen Anruf innerhalb Mono.CSharp.Driver.LoadAssembly Assembly.LoadWithPartialName, oder gehen Sie wie folgt in meiner Anwendung

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

auf Mono die gleiche Wiederverwendung machen Dynamische Assembly für jeden Evaluate/Compile-Aufruf, alles was ich ändern musste, ist folgender (obwohl es wahrscheinlich Komplexitäten gibt, die mir hier fehlen) ...

Inside Mon.CSharp.Evaluator, fügte ich die Eigenschaft:

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

Dann ... stellen Sie sicher, Reset mindestens einmal in Init genannt:

static void Init() 
    { 
     Init (new string [0]); 
     Reset(); 
    } 

Und schließlich, in ParseString, einfach nicht zurückgesetzt, es sei denn Autoreset ist wahr ...

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

Also, ich habe das gleiche Problem. Gibt es eine kompilierte Version von Mono.CSharp.dll mit den oben beschriebenen Änderungen? Ich möchte das in einer Anwendung verwenden, aber ich finde es sehr instabil. –

+0

Welches Problem haben Sie? Haben Sie versucht, die oben genannten Änderungen vorzunehmen? Wenn Sie es wirklich brauchen, kann ich eine DLL zur Verfügung stellen, aber Sie sind wahrscheinlich besser dran, nur diese Änderungen vorzunehmen und die DLL selbst zu kompilieren. – Jeff

+0

Auch an meinem Ende, nachdem ich diese Änderungen vorgenommen habe, habe ich nicht wirklich irgendwelche anderen Probleme gesehen ... hast du? – Jeff

1

Laut Miguels Blog-Seite, die Sie verlinkt haben, müssen Sie einen Verweis auf System.Core hinzufügen, um LINQ auf .Net zu verwenden.

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

Ah ... Ich sehe, aber das Hinzufügen eines Verweises ist nicht genug, da GAC-Assemblys oder Framework-Assemblys nicht in das Verzeichnis bin kopiert werden. – Jeff