Hallo Leute!
Ich hatte ja hier mal die Projekte Funktionsplotter und Formeleditor veröffentlicht.
Diese nutzen für die Funktionalität zur Laufzeit übersetzten Code.
Jetzt kam ich gestern auf die Idee das ganze von außen zu erweitern, in dem ich an einer Stelle einen Lambda-Ausdruck verwende, dieser ist Basis für ein Delegate
das an eine Klasse übergeben wird, die diesen Ausdruck auswertet bzw. ausführt.
Wenn ich keinen zur Laufzeit übersetzten Code benutze, funktioniert das ganze.
Wenn ich aber den oben beschriebenen Mechanismus benutze, behauptet der Compiler es würde eine ")" fehlen. Füge ich eine hinzu, verlangt er noch eine usw.
Jetzt meine Frage:
Ist es möglich, dass man etwas spezielles beachten muss, wenn man einen Lambda-Ausdruck auf die oben beschriebene Methode zur Laufzeit kompilieren möchte?
P.S.:
Falls das ganze nicht ganz klar ist, ich kann auch gerne den generierten Code und das Projekt dazu posten.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
das musst du durch die Expression<T> klasse schleusen. diese hat dann eine Compile methode, welche dir dann irgendwie etwas IL code leifert oder so ähnlich. ich baue mir privat auch sowas für wpf und bindings, damit ich ein wenig mehr tricksen kann aber ich konnte ncoh nicht ausreichend zeit investieren um durchzusteigen.
@JAck30lena:
Ok, das erklärt das Problem. 😉 Denn der generierte Code ist eine vollständige in C# generierte Klasse und lässt sich nämlich im Compiler ohne Probleme MIT Lambda-Ausdruck komplett übersetzen.
Aber auch wenn ich den Lambda-Ausdruck herauswerfe und das Projekt komplett zur Laufzeit kompilieren lasse, funktioniert es.
Dann werde ich wohl auch mal Zeit investieren müssen. Können wir uns ja gegenseitig helfen. 😉
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Hallo dr4g0n76
Stichwort: Expression Tree, Artikel dazu: [Artikel] Delegaten, anonyme Methoden, Lambda-Ausdrücke & Co.
Ein ExpressionTree bildet schlussendlich nur eine Funktion ab, nicht mehr und nicht weniger.
Daher denke ich, das es für dich nicht geeignet ist, so wie du dein Szenario beschreibst.
Gruss Peter
--
Microsoft MVP - Visual Developer ASP / ASP.NET, Switzerland 2007 - 2011
Danke für den Tipp @ Peter Bucher,
hier ist ebenfalls etwas womit man einen Versuch starten könnte:
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
hier habe ich noch etwas interessantes:
http://www.ohloh.net/p/linq2codedom
Hallo dr4g0n76,
Falls das ganze nicht ganz klar ist...
Hm, so ganz hab ich's noch nicht... Willst du aus einer Zeichenkette (die einen Lambda-Ausdruck darstellt) zur Laufzeit auswerten und dann "ausführen"? Dann hilft dir vielleicht
Expression<Func<T, T>> aus string erzeugen?
Gruß,
dN!3L
@dN!3L:
Untenstehende Klasse wird zur Laufzeit erzeugt als String und dann kompiliert.
using LambdaImageProcessing;
using System.Drawing;
public class LambdaScript
{
LambdaCommand command = new LambdaCommand();
public LambdaScript()
{
}
public void Test(Bitmap _bitmap)
{
command.Apply(_bitmap,
(Color c, int x, int y) => Color.FromArgb(c.R, c.G, c.B) // <== hier
);
}
}
An der fett markierten Zeile stört sich der Compiler zur Laufzeit, wenn ich die entsprechenden Befehle benutze und dann CompileFromSourceCode aufrufe.
Die Fehlermeldung die ich erhalte:
) erwartet.
Genau diesen String, nicht mehr und nicht weniger erhalte ich, eine ")" hinzuzufügen, kann ich so oft ich will der Fehler bleibt immer gleich.
Wird die Klasse aber genau so in das Projekt DIREKT eingebunden und NICHT zur Laufzeit generiert, kann Visual Studio das ganze ohne Probleme übersetzen und ausführen.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Kann sein dass ich da jetzt daneben liege, aber:
ich kompilere mit CodeDom zur Laufzeit code (string => dll)
und da musste ich dem CodeDom Compiler sagen das ich 3.5 haben will
vielleicht fehlt das da einfach auch.
so in der Nähe von CompilerVersion("3.5");
Der Link passt zwar nicht ganz zum Thema aber die angesprochene Zeile kommt vor.
CompilerVersion
Ich weis dass Du was anderes hast, aber vielleicht konnte ich eine Richtung vorgeben.
// Edit:
bei mir hatte er ohne der richtigen Compiler version nämlich genau probleme mit dem Lambda, ohne lambda gings auch ohne Compilerversion
Wenn es bei dir ohne Lambda geht, würde ich in die gleiche Richtung tippen.
mbg
Rossegger Robert
mehr fragen mehr wissen
Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen
@spike24:
Danke für den Hinweis:
anscheinend geht auch so was:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
class Program
{
static void Main(string[] args)
{
var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "foo.exe", true);
parameters.GenerateExecutable = true;
CompilerResults results = csc.CompileAssemblyFromSource(parameters,
@"using System.Linq;
class Program {
public static void Main(string[] args) {
var q = from i in Enumerable.Range(1,100)
where i % 2 == 0
select i;
}
}");
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
}
}
Wichtig ist anscheinend, dass es eben NICHT "3.5" sondern explizit "v3.5" heißen muss, d.h. das v ist wichtig.
Danke für den Hinweis. 😉
d.h. in meinem Code habe ich jetzt:
public CReflectiveEvaluator()
: this(new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } }))
{
}
geschrieben. Was tatsächlich eine Änderung bewirkt, nur kann jetzt der Typ zur Laufzeit nicht erstellt werden. Die Kompilierung schlägt aber nicht mehr fehl.
EDIT:
Ich hab auf den falschen Namespace zugegriffen. Den gesamten Typnamen habe ich vollqualifiert einfach aus
compilerResults.CompiledAssembly.GetTypes()
mit dem Debugger ermittelt. Jetzt lässt sich alles übersetzen. UND.... (Test).... Geil! Läuft. Problem gelöst.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
Wenn man einen Hammer hat, sieht alles aus wie ein Nagel... 😁
@spike24: Danke, deine Lösung hats gebracht. Super Tipp!
@dN!3L: LOL. 😉 Hatte das aus einem Beispiel. Quasi zur gleichen Zeit entdeckt wie Spike den Tipp gepostet hatte:
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Hintergrund: Hier noch was ich damit gebastelt hab und warum:
string sText = new LambdaScript().Source.Replace("{0}", "Color.FromArgb(255-c.R, 255-c.G, 255-c.B)");
object obj = ev.Eval(sText, "LambdaScript", "Test", new object[] { (Bitmap)this.BackgroundImage });
Ein Benutzer soll einen Ausdruck zur Laufzeit eingeben können.
Daraus werden dann bestimmte Lambdafunktionen generiert, die dann zur Laufzeit pixelweise auf z.B. ein Bild angewendet werden können.
Auf die Idee kam ich als ich
und kurz danach dann
Steve's Techtalk C#: Image Processing and Lambda Expressions
gelesen hatte.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Kleine Ergänzung:
und da musste ich dem CodeDom Compiler sagen das ich 3.5 haben will [...]
bei mir hatte er ohne der richtigen Compiler version nämlich genau probleme mit dem Lambda, ohne lambda gings auch ohne Compilerversion
Das liegt daran, dass Lambdaausdrücke/Expressions ein Compilerfeature/C# 3.0-Feature (nicht zu verwechseln mit .NET-Framework-Version) sind.
Allerdings hätte ich erwartet, dass der aktuellste Compiler/die neueste C#-Version benutzt wird. Wieder was über CodeDOM gelernt...
Gruß,
dN!3L
Hier noch das Testprojekt dazu.
Und die Erklärung:
WindowsFormsApplication1 ist das Projekt mit der Form.
LambdaImageProcessingTools enthält die Routinen zum probieren
und ScriptCompiler2 ist eine Weiterentwicklung des Runtime-Compilers von FormelEditor bzw. Funktionsplotter, mit dem Unterschied zu früher, dass jetzt beliebige Objekte hin- und hergereicht werden können, wie ihr seht.
In diesem Fall eben ein Bild, das reingesteckt, über den Runtime-Lambda-Ausdruck verarbeitet, und dann wieder als Hintergrundbild der Form angezeigt wird.
Es wird also wirklich in den Lambda-Ausdruck reinkompiliert was in die Textbox eingegeben wird.
Das ganze ist nur ein Probierprojekt. Funktioniert aber super, solange beim Eintippen keine Fehler passieren.
EDIT: Ach ja, ganz vergessen, wichtig! Um ein Bild zu laden, Hintergrund mit Links doppelklicken, sonst gibts ne Exception oder evtl. andere Fehler
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Hallo zusammen,
und da musste ich dem CodeDom Compiler sagen das ich 3.5 haben will
Bekommt man eigentlich irgendwie raus, welche Compilerversion man (maximal) zur Verfügung hat?
Mit Environment.Version
kommt man ja an die CLR-Version, aber die stimmt ja nicht mit der Compilerversion überein...
Gruß,
dN!3L
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
Wenn man einen Hammer hat, sieht alles aus wie ein Nagel... 😄
Ist das eigentlich positiv oder negativ gemeint?!
EDIT/EDIT: 🙂 wie gehen hier nochmal die richtigen Smilies?! ^^
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.
Ich glaube weder noch, meines Erachtens beschreibt es eher die Situation, dass man etwas neues gelernt hat und mit diesem neuen wissen versucht alle bestehenden Probleme zu lösen.
Regular Expressions
mbg
Rossegger Robert
mehr fragen mehr wissen
Montag morgen ist die beste Zeit um eine erfolgreiche Woche zu beginnen
Falls es jemanden interessiert, inzwischen habe ich auch folgendes gelöst:
LINQ Ausdruck zur Laufzeit übergeben.
Im eigentlichen geht das analog mit der selben Technik.
Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.