看看表达式树是如何在 Microsoft .NET 的System.Linq.Expressions命名空间中建模的很有趣。我认为在这里很重要的基本概念是,一切都继承自基本的Expression类——所以几乎所有东西都是一个表达式,无论是二元运算、参数、常量等等。
此外,NuGet 包Serialize.Linq演示了如何将此类表达式树序列化为 XML。
长解决方案
不过这只是参考。我认为 XML 模型可以做得更简单。我会像这样为您的示例建模:
<expr returns="boolean">
<params>
<param name="x" type="boolean">
<param name="y" type="boolean">
<param name="p" type="boolean">
<param name="q" type="boolean">
</params>
<body op="bor">
<left op="band">
<left op="param">x</left>
<right op="param">y</left>
</left>
<right op="band">
<left op="param">p</left>
<right op="param">q</left>
</right>
</body>
<expr>
简短的解决方案
根据您的实现,您可能能够省略<params>
元素和type
属性,并在解释表达式时以更“隐式”的方式处理这些事情(有点像 JavaScript、PowerShell 等)。此外,如果 XML 输出的大小/长度存在问题,您可以缩短元素和类型名称。
因此,这是一个高度缩短版本的示例:
<e t="bor">
<l t="band">
<l t="prm">x</l>
<r t="prm">y</r>
</l>
<r t="band">
<l t="prm">p</l>
<r t="prm">y</r>
</r>
</e>
另一个例子
为了完整起见,这里是另一个示例,说明如何以这种方式对更复杂的表达式进行建模。
伪代码 lambda/箭头表达式:
(float b, int e) => e == 0 ? 1 : (e == 1 ? b : pow(b, e))
XML 表示:
<expr returns="float">
<params>
<prm name="b" type="float" />
<prm name="e" type="int" />
</params>
<body op="if">
<cond op="eq">
<left op="param">e</left>
<right op="const" type="int">0</right>
</cond>
<true op="const" type="float">1</true>
<false op="if">
<cond op="eq">
<left op="param">e</left>
<right op="const" type="int">1</right>
</cond>
<true op="param">b</true>
<false op="call" name="pow">
<args>
<arg op="param">p</arg>
<arg op="param">e</arg>
</args>
</false>
</false>
</body>
</expr>