是否可以为动态if语句创建表达式树?

时间:2012-03-23 18:26:34

标签: c# lambda

我有一个situtaiton,我在那里阅读业务逻辑并用实际值替换变量,然后我需要评估它以获得结果。我目前正在使用bcParser来做它,并且它适用于所有像excel格式编写的逻辑。

向我抛出的曲线球是,if条件不会像excel if(cond, true, false),而是它将像C#if (cond) { true; } else { false;},这更有意义,更容易维护。由于我事先用值替换了所有变量,我所要做的就是评估它。目前我通过将逻辑导出到c#方法并使用反射来解决这个问题我正在评估它并且它也有效。

我想知道是否还有其他选项,我不想为每个if条件编写代码,并希望在运行时对其进行评估。我想知道我是否应该能够创建某种类型的令牌解析器并调用C#本机表达式求值并执行计算。我还没有理解表达树,似乎有可能采用这种方法。在我去那里之前,我想知道它有可能吗? 谢谢,

1 个答案:

答案 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的神奇之处。