在编程语言的世界里,C#表达式树是一个令人着迷的话题。它们允许分析C#代码,并以不同的方式重新解释它。例如,LINQ-to-SQL可以将C#中编写的表达式转换成SQL语句。本文将展示如何将C#代码的一个子集转换成8086机器码,这是一种非常基础的机器语言,用于早期的PC计算机。
尽管阅读了许多关于LINQ表达式树的博客,并且了解到它们非常“酷”,但是很少有文章真正解释了表达式树的用途。本文将通过一个示例来展示表达式树的一种可能的应用。将来,可能会扩展这篇文章,进一步讨论表达式树在编程中的作用。
选择了.com文件,因为它们是最简单的可执行文件格式。它们仅仅是8086机器码的数组,没有任何头部或元数据。对于编译器编写者来说,这是天堂。而且,它们仍然可以在所有版本的Windows上执行。
请注意,这里的"com"只是一个文件扩展名,例如xy.com,它与大约10年后出现的组件对象模型(Component Object Model)无关。
表达式可能包含变量和三种算术运算:+、-和*。所有的算术运算都是在无符号的16位整数中进行的。
当生成的COM文件执行时,它会打印一个横幅,提示用户输入参数值(如果有的话),计算结果并显示它。COM文件应该在控制台窗口中执行,例如从cmd.exe。
例如,表达式(x,y) => 2*x + 3*y在编译和执行后会产生以下输出(用户输入加粗显示):
C# for MS-DOS, version 1.0
x?
10
y?
20
((2 * x) + (3 * y)) = 80
示例提供了一个名为ExpressionCompiler86的类,其中包含一个名为Compile的方法。以下是主类Program如何编译三个表达式的示例:
// 一个简化的小包装器
static void Compile(string file, Expression expr)
{
using (ExpressionCompiler86 compiler = new ExpressionCompiler86(file))
{
compiler.Compile(expr);
}
}
...
Compile>(
"constant.com",
() => 42
);
Compile>(
"noparams.com",
() => 1+2+3*4
);
Compile>(
"xy.com",
(x, y) => 2*x + 3*y
);