打印源代码-C#

    这两天随便翻了一下.Net程序员面试宝典,发现一个很有意思的题目:编写一个程序将此程序的源代码原封不动的打印出来,也就是说程序运行后在命令行上面打印的内容和源代码完全相同。如果不仔细思考,可能我们会立即开始编码,然后想用Console.WriteLine来搞定这个问题,但有两个棘手的问题得解决。

    1. 如果我们直接在Main方法里用Console.WriteLine来打印,大概的样子是:Console.WriteLine("/*Console.WriteLine前面的代码*/Console.WriteLine("/*代码内容*/");/*Console.WriteLine后面的代码*/")。这样/*代码内容*/部分又得将整个源代码重复一遍,最终得折腾出一个类似死循环或无限递归一样的东西。
    2. 对于转义字符,也有同样的问题。例如我们源码里面的双引号,在源码里是双引号,我们在字符串里却得写成‘\"’转义一下,但是这样的话源码就变成了‘\"’,这样我们的字符串就得改成‘\\\"’,这样源码里面的字符串就变成了‘\\\"’,如此下去,也是死递归。

解决方法如下:

    1. 定义一个字符窗保存源码内容,例如‘s="/*源码内容*/";’。‘/*源码内容*/’可以直接将s字符串赋值这个语句之外的其他源码填充进去,而s字符串赋值中的内容则改为一个参数,在打印的时候将s作为一个额外参数格式化。这样s字符串赋值语句就变成了:‘s=/*s赋值语句前面的源码*/s=\"{0}\";/*s赋值语句后面的源码*/’。打印语句就变成了‘Console.WriteLine(s,s);’。

    2.对于转义字符,我们也得将其变成一个参数来格式化字符串。由于死递归,我们不能在源码中使用反斜杠的语法,而是用其他方式,例如将字符的ascii码直接强转成字符。例如,双引号可以写成‘(char)34’;

 

最终得到以下的代码:

 

1 using System;
2  public class PrintSelf {
3 public static void Main(string[] args) {
4 string s =
5  "using System;{1}public class PrintSelf {{{1} public static void Main(string[] args) {{{1} string s ={1}{2}{0}{2};{1} Console.WriteLine(s,s,System.Environment.NewLine,(char)34);{1} }}{1}}}";
6 Console.WriteLine(s,s,System.Environment.NewLine,(char)34);
7 }
8 }
posted @ 2010-12-19 14:15  李土鳖  阅读(1603)  评论(2编辑  收藏  举报