Frage

Ich brauche meine Benutzer ermöglichen zu können, Formeln definieren, welche Werte auf Basis von Daten errechnet. Zum Beispiel

//Example 1
return GetMonetaryAmountFromDatabase("Amount due") * 1.2;
//Example 2
return GetMonetaryAmountFromDatabase("Amount due") * GetFactorFromDatabase("Discount");

Ich muß / ermöglichen * + - Operationen, auch lokale Variablen zuweisen und IF-Anweisungen ausführen, wie so

var amountDue = GetMonetaryAmountFromDatabase("Amount due");
if (amountDue > 100000) return amountDue * 0.75;
if (amountDue > 50000) return amountDue * 0.9;
return amountDue;

Das Szenario ist kompliziert, weil ich die folgende Struktur haben ..

  1. Kunde (ein paar hundert)
  2. Konfiguration (etwa 10 pro Kunde)
  3. Artikel (etwa 10.000 pro Kundenkonfiguration)

Also habe ich eine 3-Level-Schleife durchführen wird. Bei jeder „Konfiguration“ Ebene werde ich eine DB-Transaktion starten und die forumlas kompiliert, die jeweils „Item“ die gleiche Transaktion + kompilierte Formeln verwenden (es gibt etwa 20 Formeln pro Konfiguration wird jedes Element alle von ihnen).

Diese weiteren verkompliziert die Dinge, weil ich nicht nur die Compiler-Dienste verwenden kann, wie es in Fortsetzung Speichernutzung Wachstum führen würde. Ich kann nicht eine neue AppDomain pro jeder „Konfiguration“ Loop-Ebene verwenden, da einige der Referenzen, die ich passieren müssen nicht rangieren.

Irgendwelche Vorschläge?

- Update-- Dies ist, was ich ging mit, danke! http://www.codeproject.com/Articles/53611/ Embedding-Ironpython-in-aC-Anwendung

War es hilfreich?

Lösung

Sie können eine einfache Klasse zur Laufzeit erstellen, nur durch Ihre Logik in einen String oder dergleichen zu schreiben, kompilieren, führen Sie es und machen es die Berechnungen zurückkehren Sie benötigen. Dieser Artikel zeigt Ihnen, wie der Compiler Laufzeit zuzugreifen: http: //www.codeproject. com / KB / cs / codecompilation.aspx

Andere Tipps

Eisen Python Erlaubt ein Scripting-Engine in Ihre Anwendung einbetten. Es gibt viele andere Lösungen. In der Tat können Sie so etwas wie „C # eingebettet Scripting“ Google und eine ganze Reihe von Optionen. Einige sind leichter als andere zu integrieren, und einige sind leichter als andere, um Code auf den Skripten.

Natürlich gibt es immer VBA. Aber das ist nur geradezu hässlich.

stand ich ein ähnliches Problem vor ein paar Jahren. Ich hatte ein Web-App mit mäßigem Verkehr, die Gleichungen lassen mußte, und es brauchte ähnliche Funktionen bei Ihnen, und es mußte schnell sein. Ich ging durch mehrere Ideen.

Die erste Lösung berechnete Spalten zu unserer Datenbank beteiligt hinzufügen. Unsere Tische für die App speichern Sie die Eigenschaften in Spalten (zum Beispiel gibt es eine Spalte für Amount Due, einen anderen Rabatt, etc.). Wenn der Benutzer in einer Formel wie propertyâ getippt * 2, verändern würde der Code die zugrundeliegende Tabelle eine neue berechnete Spalte zu haben. Es ist chaotisch so weit wie das Hinzufügen und Entfernen von Spalten. Es hat ein paar Vorteile haben aber: die Datenbank (SQL Server), die Berechnungen war wirklich schnell zu tun; die Datenbank eine Menge Fehlererkennung für uns behandelt; und ich konnte so tun, dass die berechneten Werte die gleichen wie die nicht berechneten Werte waren, was bedeutete, dass ich nicht alle vorhandenen Code modifizieren musste, die mit den nicht-berechneten Werten gearbeitet.

Das ist für eine Weile gearbeitet, bis wir die Möglichkeit, eine Formel, eine andere Formel zu verweisen benötigt, und SQL Server nicht, dass erlauben. Also wechselte ich zu einem Scripting-Engine. Ironpython war nicht sehr reifen dann zurück, so dass ich einen anderen Motor wählte ... Ich kann mich nicht erinnern, eine, die gerade jetzt. Wie auch immer, es war zu schreiben, einfach, aber es war ein wenig langsam. Nicht viel, vielleicht ein paar Millisekunden pro Abfrage, aber für einen Web-App der Zeit wirklich über alle Anfragen aufaddiert.

Das war, als ich beschloss, meine eigenen Parser für die Formeln zu schreiben. Das heißt, ich PlusToken Klasse haben zwei Werte hinzuzufügen, eine ItemToken Klasse, entspricht GetValue ( „Discount“) usw. Wenn der Benutzer eine neue Formel eintritt, eine Prüfung der Formel analysiert, stellt sicher, dass es gültig ist (Dinge wie: haben sie verweisen auf eine Spalte, die nicht vorhanden ist?), und speichert sie in einem halb-kompilierter Form, die später leicht zu analysieren ist. Wenn der Benutzer einen berechneten Wert anfordert, liest ein Parser die Formel, analysiert ihn, Zahlen, welche Daten aus der Datenbank benötigt wird, und berechnet die endgültige Antwort. Es dauerte eine Menge Arbeit nach vorne, aber es funktioniert gut und es ist wirklich schnell. Hier ist, was ich gelernt habe:

  1. Wenn der Benutzer eine Formel gelangt, dass in den Formeln zu einem Zyklus führt, und Sie versuchen, den Wert der Formel zu berechnen, werden Sie aus Stapelspeicher laufen. Wenn Sie diese auf einem Web-App laufen, stoppt der gesamte Web-Server arbeiten, bis Sie es zurücksetzen. Deshalb ist es wichtig Zyklen in der Validierungsphase zu erkennen.
  2. Wenn Sie mehr als ein paar Formeln haben, aggregieren alle Datenbankaufrufe an einem Ort, dann fordern Sie alle Daten auf einmal. Viel schneller.
  3. Die Benutzer geben verrückte Sachen in Formeln. Ein Parser, der nützliche Fehlermeldungen liefert eine Menge Kopfschmerzen sparen später.

Wenn die benutzerdefinierte Skripts als die, die nicht komplexer werden, dass Sie oben zeigen, würde ich mit Sylvestre zustimmen: Erstellen Sie Ihre eigenen Parser, einen Baum machen und tun, die Logik selbst. Sie können eine .Net Ausdrucksbaum erzeugen oder gehen Sie einfach durch die Syntax Baum selbst und die Vorgänge in den eigenen Code machen (Antlr unten finden Sie einen solchen Code generieren helfen).

Dann sind Sie in die vollständige Kontrolle über Ihre Referenzen sind, sind Sie immer in C #, so dass Sie keine Sorgen zu machen über die Speicherverwaltung brauchen (jede mehr als Sie es normalerweise tun würde) usw. IMO Antlr ist das beste Werkzeug, das in c # zu tun. Sie erhalten Beispiele aus der Website für kleine Sprachen, wie Ihr Szenario.

Aber ... wenn dies wirklich nur einen Anfang und am Ende müssen Sie fast volle Leistung einer richtigen Skriptsprache, würden Sie in dem Einbetten eine Skriptsprache für Ihr System gehen müssen. Mit Ihren Zahlen, haben Sie ein Problem mit Performance, Speicherverwaltung und wahrscheinlich Referenzen, wie Sie zur Kenntnis genommen. Es gibt mehrere Ansätze, aber ich kann wirklich eine Empfehlung für Ihr Szenario nicht geben. Ich habe es noch nie in einem solchen Umfang durchgeführt

Sie können zwei Basisklassen UnaryOperator bauen (wenn, Quadrat, Wurzel ...) und BinaryOperator (+ - / *) und einen Baum aus dem Ausdruck bauen. Dann bewerten Sie den Baum für jedes Element.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top