Formula Engine
Die Formula Engine wertet kleine numerische Ausdrücke überall dort aus, wo die Plattform eine
vom Benutzer eingegebene Formel akzeptiert — DataPointMapping-Ausdrücke, berechnete Archivspalten und
@-Ausdrücke in Runtime-Queries. Die Ausdruckssyntax, die diese Funktionen bereitstellen, ist im Tech-Guide dokumentiert
(Formula Expressions); diese Seite
beschreibt die Engine aus Sicht eines Entwicklers: den Service-Vertrag, die zugrunde liegende
Bibliothek und die Konventionen, die jeder Aufrufer teilt.
Library
Die Engine kapselt das NuGet-Paket MathParser.org-mXparser
(aktuell v6.1.1, referenziert in Runtime.Engine.Formulas.csproj). mXparser ist ein ausgereifter
Parser für mathematische Ausdrücke; die gesamte mXparser-math collection (Funktionen, Operatoren, Konstanten) steht
Ausdrücken zur Verfügung — nichts ist deaktiviert. Da jede Eingabe und das Ergebnis ein double sind,
ist praktisch nur der numerische Teil dieser Collection nützlich (es gibt keine String-, Einheiten- oder
Objekteingaben). Siehe die
mXparser math collection für die versionsabgestimmte
Liste all dessen, was der Parser akzeptiert.
Die Bibliothek wird gekapselt statt direkt verwendet, damit die Ternär-Normalisierung, die null-/NaN- Behandlung und die Cast-back-Leiter an genau einer Stelle liegen, statt über die Aufrufer hinweg dupliziert zu werden.
IFormulaEngine
Jede Auswertung läuft über einen einzigen Dienst, IFormulaEngine
(Meshmakers.Octo.Runtime.Contracts.Formulas), implementiert durch FormulaEngine im
Projekt Runtime.Engine.Formulas. Er ist zustandslos und als Singleton über
AddFormulaEngine() registriert.
| Method | Purpose |
|---|---|
Validate(expression, arguments) | Bindet Testwerte, prüft die Syntax und wertet aus; meldet ein NaN-Ergebnis als ungültig. Untermauert den validate-expression-Endpunkt. |
CheckSyntax(expression, argumentNames) | Syntax- + Referenzprüfung ohne Auswertung — sodass eine nur zur Laufzeit auftretende Division durch null (a / (b - b)) kein False Positive ist. |
EvaluateRaw(expression, arguments) | Wertet zu einem rohen double aus. NaN = konnte nicht ausgewertet werden; -Infinity = das null-Sentinel. |
Evaluate(expression, arguments, resultType) | EvaluateRaw plus die Cast-back-Leiter; gibt null für NaN / null-Sentinel zurück. |
NormalizeTernary(expression) | Stellt das Rewrite cond ? a : b → if(cond, a, b) eigenständig bereit. |
Argumente sind immer ein IReadOnlyDictionary<string, double>; mXparser-Argumente werden namentlich
aus diesem Dictionary gebunden. Ein Ausdruck, der auf einen Namen verweist, der nicht im Dictionary ist, besteht die Syntax-
prüfung nicht.
// scale and clamp a polled value, then cast to the column's stored type
var args = new Dictionary<string, double> { ["value"] = 42.0 };
object? result = _formulaEngine.Evaluate(
"min(max(value, 0), 100)", args, FormulaResultType.Double);
Konventionen, die jeder Aufrufer teilt
Ternär-Normalisierung
Das Ternär im C-Stil cond ? a : b wird vor der Auswertung in das if(cond, a, b) von mXparser umgeschrieben
(FormulaEngine.ConvertTernaryToIf). Das Rewrite sucht nach dem passenden : auf derselben
Klammertiefe, sodass verschachtelte Ternärausdrücke und geklammerte Zweige behandelt werden:
a > 0 ? (b > 0 ? 1 : 2) : 3 → if(a > 0, (if(b > 0, 1, 2)), 3)
Validate / CheckSyntax geben die umgeschriebene Zeichenkette in NormalizedExpression zurück, sodass eine UI dem
Benutzer genau zeigen kann, was ausgewertet wurde.
Null-Sentinel und NaN
Die Engine reserviert zwei double-Werte:
double.NegativeInfinityist das null-Sentinel, den Ausdrücken alsnull- Konstante bereitgestellt. Eine fehlende / null-Eingabe bindet daran.double.NaNbedeutet, dass die Formel für diese Eingaben keinen Wert erzeugen konnte (z. B.0 / 0).
Evaluate bildet beide auf ein CLR-null ab — niemals auf eine halb fertige Zahl. Aufrufer persistieren das als SQL-
NULL (berechnete Spalten) oder greifen auf den Rohwert zurück (DataPointMapping). Validate behandelt ein
NaN-Ergebnis als ungültig, während CheckSyntax nicht auswertet und daher niemals ein
nur zur Laufzeit auftretendes NaN kennzeichnet.
Ergebnistypen und die Cast-back-Leiter
Evaluate castet das rohe double gemäß FormulaResultType zurück:
FormulaResultType | Cast-back |
|---|---|
Double | der Rohwert |
Int | auf int abgeschnitten |
Int64 | auf long abgeschnitten |
Boolean | false, wenn 0, andernfalls true |
DateTime | der Wert wird als .NET ticks interpretiert |
Der DateTime-Pfad passt zu den OctoMesh-spezifischen Funktionen now(addMinutes) und startOfDay(dayCount),
die beide DateTime-Ticks als double zurückgeben. Diese Erweiterungen sowie die null-
Konstante sind in OctoExpression registriert (NowFunction, StartOfDayFunction).
Callers
| Caller | Project | Bound variables |
|---|---|---|
ApplyDataPointMappingsNode | octo-mesh-adapter | value (der abgefragte Quellwert) — verwendet EvaluateRaw |
CrateDbStreamDataRepository (berechnete Spalten) | octo-construction-kit-engine-mongodb | jede Quellspalte über ihren physischen Spaltennamen — verwendet Evaluate mit dem gespeicherten ResultType der Spalte |
ExpressionValidationService (validate-expression-REST-Endpunkt) | octo-communication-controller-services | value (ein Testwert, Standard 42.0) — verwendet Validate |
Wenn Sie einen neuen Aufrufer hinzufügen, hängen Sie von IFormulaEngine ab und rufen Sie AddFormulaEngine() während der Dienst-
registrierung auf; referenzieren Sie mXparser nicht direkt, damit die oben genannten gemeinsamen Konventionen weiterhin gelten.