您是否考虑过使用 Mono.CSharp.Evaluator?似乎这与适当设置的 InteractiveBaseClass 结合使用可以很好地完成这个技巧,而且工作量很小。
请注意,以下使用 Mono 2.11.1 alpha。
using System;
using System.Diagnostics;
using Mono.CSharp;
using NUnit.Framework;
public class MonoExpressionEvaluator
{
[Test]
public void ProofOfConcept()
{
Evaluator evaluator = new Evaluator(new CompilerContext(new CompilerSettings(), new ConsoleReportPrinter()));
evaluator.InteractiveBaseClass = typeof (Variables);
Variables.Variable1Callback = () => 5.1;
Variables.Variable2Callback = () => 30;
var result = evaluator.Evaluate("25 + Variable1 > Variable2");
Assert.AreEqual(25 + Variables.Variable1 > Variables.Variable2, result);
Console.WriteLine(result);
}
public class Variables
{
internal static Func<double> Variable1Callback;
public static Double Variable1 { get { return Variable1Callback(); } }
internal static Func<double> Variable2Callback;
public static Double Variable2 { get { return Variable2Callback(); } }
}
}
真的很遗憾它运行有点慢。例如,在我的 i7-m620 上运行 10,000 次需要将近 8 秒:
[Test]
public void BenchmarkEvaluate()
{
Evaluator evaluator = new Evaluator(new CompilerContext(new CompilerSettings(), new ConsoleReportPrinter()));
evaluator.InteractiveBaseClass = typeof(Variables);
Variables.Variable1Callback = () => 5.1;
Variables.Variable2Callback = () => 30;
var sw = Stopwatch.StartNew();
for (int i = 1; i < 10000; i++)
evaluator.Evaluate("25 + Variable1 > Variable2");
sw.Stop();
Console.WriteLine(sw.Elapsed);
}
00:00:07.6035024
如果我们可以将其解析并编译为 IL 以便我们可以以 .NET 速度执行它,那就太好了,但这听起来有点像白日梦......
[Test]
public void BenchmarkCompiledMethod()
{
Evaluator evaluator = new Evaluator(new CompilerContext(new CompilerSettings(), new ConsoleReportPrinter()));
evaluator.InteractiveBaseClass = typeof(Variables);
Variables.Variable1Callback = () => 5.1;
Variables.Variable2Callback = () => 30;
var method = evaluator.Compile("25 + Variable1 > Variable2");
object result = null;
method(ref result);
Assert.AreEqual(25 + Variables.Variable1 > Variables.Variable2, result);
Variables.Variable2Callback = () => 31;
method(ref result);
Assert.AreEqual(25 + Variables.Variable1 > Variables.Variable2, result);
var sw = Stopwatch.StartNew();
for (int i = 1; i < 10000; i++)
method(ref result);
sw.Stop();
Console.WriteLine(sw.Elapsed);
}
00:00:00.0003799
天哪。
需要像 IF 这样的类似 excel 的表达式结构吗?建立你自己的!
[Test]
public void ProofOfConcept2()
{
Evaluator evaluator = new Evaluator(new CompilerContext(new CompilerSettings(), new ConsoleReportPrinter()));
evaluator.InteractiveBaseClass = typeof(Variables2);
Variables.Variable1Callback = () => 5.1;
Variables.Variable2Callback = () => 30;
var result = evaluator.Evaluate(@"IF(25 + Variable1 > Variable2, ""TRUE"", ""FALSE"")");
Assert.AreEqual("TRUE", result);
Console.WriteLine(result);
}
public class Variables2 : Variables
{
public static T IF<T>(bool expr, T trueValue, T falseValue)
{
return expr ? trueValue : falseValue;
}
}