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

本文关键字:一个 表达式 创建 动态 语句 if 是否 | 更新日期: 2023-09-27 18:28:45

我有一个位置,在那里我读取业务逻辑并用实际值替换变量,然后我需要对其进行评估以获得结果。我目前正在使用bcParser来做这件事,它对所有像excel格式一样编写的逻辑都很好。

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

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

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

是!

密钥使用System.Linq.Expressions命名空间。您可以在代码中或通过修改解析器以编程方式构建表达式树,然后将其编译为Delegate。此API在DynamicAssembly内部编译Delegate,这意味着当您完全取消引用已编译的表达式时,垃圾收集器可以将它们从内存中卸载。

这里有一个非常简单的例子:

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的神奇内脏。