我有一个situtaiton,我在那里阅读业务逻辑并用实际值替换变量,然后我需要评估它以获得结果。我目前正在使用bcParser来做它,并且它适用于所有像excel格式编写的逻辑。
向我抛出的曲线球是,if条件不会像excel if(cond, true, false)
,而是它将像C#if (cond) { true; } else { false;}
,这更有意义,更容易维护。由于我事先用值替换了所有变量,我所要做的就是评估它。目前我通过将逻辑导出到c#方法并使用反射来解决这个问题我正在评估它并且它也有效。
我想知道是否还有其他选项,我不想为每个if条件编写代码,并希望在运行时对其进行评估。我想知道我是否应该能够创建某种类型的令牌解析器并调用C#本机表达式求值并执行计算。我还没有理解表达树,似乎有可能采用这种方法。在我去那里之前,我想知道它有可能吗? 谢谢,
答案 0 :(得分:5)
是!
关键是使用System.Linq.Expressions
命名空间。您可以在代码中以编程方式构建表达式树,也可以修改解析器,然后将其编译为Delegate
。此API在Delegate
内部编译DynamicAssembly
,这意味着当您完全取消引用它们时,垃圾收集器可以从内存中卸载已编译的表达式。
这是一个非常简单的例子:
var b = true;
Func<bool> condition = () => b;
Action trueExpression = () => { Console.WriteLine(true); };
Action falseExpression = () => { Console.WriteLine(false); };
var e = Expression.Condition(
Expression.Invoke(Expression.Constant(condition)),
Expression.Invoke(Expression.Constant(trueExpression)),
Expression.Invoke(Expression.Constant(falseExpression)));
var λ = Expression.Lambda(e).Compile();
b = true;
λ.DynamicInvoke();
b = false;
λ.DynamicInvoke();
这会产生输出:
True
False
将表达式编译为Lambda的步骤可能会受到重大影响,您将需要为已编译的lambda提出缓存策略。尽管如此,使用DynamicInvoke调用编译的lambda非常快。几乎和你预先编译它一样快。这种技术比使用CodeDom代码生成要快得多(这需要另外一个进程来完成编译),并且它具有生成无法加载程序集的主要优点。
唯一的限制是您无法使用此API创建类型。你必须限制自己的表达和陈述。然而,它非常强大,这是DLR的神奇之处。