Zuerst habe ich im Netz nachgesehen und kam auf JScript, dass die Methode Eval benutzt. Diesen Code habe ich dann auch im Projekt belassen.
Aber ich wollte dann eigentlich doch etwas komfortableres haben, das ausbaubarer ist als JScript.
Also habe ich mit C# und dem Compiler eine eigene "Eval"-Funktionalität kreiert. Die übrigens sehr gut funktioniert.
Im Constructor werden die Compiler-Parameter initialisiert und Referenzen auf die benötigten DLLs eingestellt:
public CReflectiveEvaluator()
{
m_CSharpCodeProvider = new CSharpCodeProvider();
this.m_ICodeCompiler = m_CSharpCodeProvider.CreateCompiler();
m_CompilerParameters = new CompilerParameters();
m_CompilerParameters.GenerateInMemory = true;
m_CompilerParameters.GenerateExecutable = false;
m_CompilerParameters.ReferencedAssemblies.Add("system.dll");
m_CompilerParameters.ReferencedAssemblies.Add("mscorlib.dll");
}
und in eval wird der Code ausgeführt:
public object Eval(string _sFormula)
{
string sSource = this.m_sFormulaTemplateClass.Replace("{1}",_sFormula);
sSource = sSource.Replace("{0}",CreateVariablesDeclarationsInstructions());
System.CodeDom.Compiler.CompilerResults cr = m_ICodeCompiler.CompileAssemblyFromSource(this.m_CompilerParameters, sSource);
Type tMathEval = cr.CompiledAssembly.GetType("CMathEval");
object oMathEval = Activator.CreateInstance(tMathEval);
object o = oMathEval.GetType().GetMethod("Eval").Invoke(oMathEval, null);
return o;
}
Hier kommt noch ein kleiner Trick vor:
Der Konstruktor von der Eval-Klasse sieht so aus:
public object Eval()
{
{0}
object o = null;
o={1};
return o;
}
Zur Laufzeit werden jetzt die Variablen in {0} geschrieben (mittels String.Replace)
und in {1} wird genau auf die gleiche Weise, die Formel eingefügt.
Wenn jetzt jemand in den Formeleditor z.B. die Variable
a = 5;
und die Formel 4*a eingibt,
dann wird daraus:
public object Eval()
{
double a = 5;
object o = null;
o=4*a;
return o;
}
Es ist kaum zu glauben, aber das ist alles was benötigt wird, um den Code zu erzeugen und zur Laufzeit auszuführen.
Das Ergebnis wird dann per Invoke ermittelt in die Ergebnis-Textbox eingefügt.