现在的位置: 首页 > 综合 > 正文

动态生成与编译(三)—-写一个面向过程的程序

2011年02月08日 ⁄ 综合 ⁄ 共 4501字 ⁄ 字号 评论关闭

 

先讲一个简单的程序,把变量声明、赋值、if语句、for循环等讲掉,这些是程序的基本的东东,再顺便带一下异常处理。就是一个比()复杂一点的控制台程序而已,关于类方面的东西下次再来。

找来找去找了个Fibonacci数列的程序,这个输入输出比较的简单,而且基本流程代码都有。当然真的实际生成不会去生成这种的程序,现在主要是“借”它一用。

先看生成的程序,下面就是用CodeDOM生成的代码:

namespace Sample {

    using System;

   

   

public class DemoClass {

       public static void Main() {

            System.Console.WriteLine("输入 n的值:");

            string Nstr = System.Console.In.ReadLine();

            try {

                int N = System.Convert.ToInt32(Nstr);

                if ((N >= 1)) {

                    Fibonc(N);

                }

                else {

                    System.Console.WriteLine("n 必须大于0");

                }

            }

            catch (System.Exception ex) {

                System.Console.WriteLine(ex.Message);

            }

            System.Console.Read();

        }

       

        // Fibonacci数列

        private static void Fibonc(int n) {

            int F;

            int F1 = 0;

            int F2 = 1;

            for (int i = 1; (i <= n); i = (i + 1)){

                F = (F1 + F2);

                System.Console.WriteLine("{0},Fibonacci:{1}", i, F);

                F1 = F2;

                F2 = F;

            }

     }

}

}

因为一直找不到生成while循环的方法(for代替当然也可以,但看起来比较怪怪的),所以程序比较的弱智点,错了就得重来。

 

那个Main()先放着,先看下面这个求Fibonacci数列的方法,先要把它定义出来,

                CodeMemberMethod FiboncMethod = new CodeMemberMethod();

                FiboncMethod.Comments.Add(new CodeCommentStatement("Fibonacci数列"));

                FiboncMethod.Name = "Fibonc";//方法名

                FiboncMethod.Attributes =  MemberAttributes.Private | MemberAttributes.Static;//可见性

                FiboncMethod.Parameters.Add(new CodeParameterDeclarationExpression(typeof(int),"n"));//参数

 

任何一个方法总归是要有归宿的,所以它是MemberMethod,是属于某个TypeMember,在()中讲过,CodeMemberMethod是从CodeTypeMember继承来的。new出来,加注释,取名,设置可见性(到处属性属性的人都要晕了,用可见性比较好)都没什么好说的。

最后加参数出来一个新东西CodeParameterDeclarationExpression,好长呀,直译叫参数声明表达式,它的构造函数一看就明白,定义了类型跟名字。在CodeDOM里很多类的构造函数都是有好几种形式的,象上面这个就有3(Type,string)(string,string)(CodeTypeReference,string)

上面程序中用的就是(Type,string)这种形式了;第二种是直接用类型名来代替,不过要注意对于象int这样的基础类型如果写成("int","n")它会生成Fibonc(@int n),显然这不是我们想要的,它应该写成("System.Int32","n");至于第三种在这里没有任何的吸引力要这样写(new CodeTypeReference("System.Int32"),"n")) 太累了,用在那种数据类型也是用代码生成的情况下比较的有用。

 

定义好了方法,一开始就是变量声明,变量声明用的是CodeVariableDeclarationStatement int F2 = 1;这一句是这样来的:

CodeVariableDeclarationStatement VarF2 = new CodeVariableDeclarationStatement(typeof(int),"F2",new CodePrimitiveExpression(1));

 

这个跟参数声明差不多,唯一不同的是变量声明有个赋初始值问题,当然不象上面那样在构造函数里赋初始值,而是设置VarF2InitExpression属性也是能产生一样的效果的。InitExprsssion属性是CodeExpression类型的,在()说到过这个CodeExpression是很丰富的东西,上面的CodePrimitiveExpression也是CodeExpression的一种,Primitive的意思就是“原始的”的意思,它把括号里的东西原样的拿出来,它能表示各种整数、各种浮点数、字符串及空引用(nullNothing)

 

下面的for循环比较的麻烦,把它分解出来一点一点的讲。

循环的初始化部分是一个变量声明语句,声明了一个i并赋初值为1,它的写法上面说过了,略过。第二部分测试表达式要用到一个新的CodeExpressionCodeBinaryOperatorExpression

CodeBinaryOperatorExpression test = new CodeBinaryOperatorExpression(new CodeVariableReferenceExpression("i"),

                 CodeBinaryOperatorType.LessThanOrEqual,new CodeArgumentReferenceExpression("n"));

 

它的构造函数看起来很长的样子,其实是很容易理解的,三个参数分别是左表达式、运算符、右表达式。这里左边是个变量i,所以用上了CodeVariableReferenceExpression(就叫变量引用了),右边是个方法带的参数n CodeArgumentReferenceExpression(那就是参数引用了)来取。中间那个表示运算符的CodeBinaryOperatorType是个枚举,什么加减乘除、大小等于、与或之类的都有。(不过这个CodeBinaryOperatorExpression是表示二元运算的,到现在还没找到一元运算应该怎么办,比如取反,这个运算还是有点用的)

第三部分的i = (i + 1)是一个赋值语句,赋值语句用CodeAssignStatement来产生,它比运算表达式简单那么一点点,左右都是有的,只是中间的运算符没了。如下:

CodeAssignStatement increment = new CodeAssignStatement(new CodeVariableReferenceExpression("i"), new CodeBinaryOperatorExpression(。。。));

这个赋值语句左边是个变量,右边同时又是一个运算表达式,所以又new 了一个CodeBinaryOperatorExpression,全写出来太长了,这里略。

for循环完了,没有,只是上头好了,循环体内还有四句呢。在CodeDOM里,整个for循环的所有语句都是要组成一个大的CodeStatement的。在循环体内第一、三、四句都是赋值语句,不进了。讲讲第二句,方法调用。方法调用表达式CodeMethodInvokeExpressionCodeDOM里使用频率非常高的一个CodeExpression,现在写程序没有可能会一路走到底的,总要会调用到方法。CodeMethodInvokeExpression的一个构造函数如下:

public CodeMethodInvokeExpression(

   CodeExpression targetObject,
   string methodName,
   params CodeExpression[] parameters
);

第一个参数是调用方法的目标对象,是一个CodeExpression,在这个程序里用的是CodeTypeReferenceExpression(注意它与CodeTypeReference的区别,其实如果直接看中文的文档的解释那简直是云里雾里的,还是直接从字面上理解省事,其中一个是Expression,一个不是,二者用的地方不一样,其实是差不多的东西,我这是这样理解的)。第二个参数没什么好说的,一看就明白了。第三个参数是个数组,CodeExpression的数组,调用的方法有几个参数,这数组里就有几个CodeExpression,方法无参的话这个参数可省略(文档里没提到这点,刚开始以为要new 一个空数组在那里的,后来发现不用。如这个程序里的WriteLine有三个参数,那就有三个CodeExpression,分别是一个CodePrimitiveExpression、二个CodeVariableReferenceExpression

()里说过CodeExpression一般情况下是不能当语句的,所以上面的那个CodeMethodInvokeExpression要转一下,用CodeExpressionStatement包一下就好了(直接把上面产生的CodeMethodInvokeExpression放到CodeExpressionStatement构造函数里就OK)

循环的每一部分都分解完了,现在大家伙要登场了。产生for循环语句的CodeStatement----CodeIterationStatement

抱歉!评论已关闭.