• 动态生成与编译(四)用CodeDOM生成一个完整的类(上)


     

     

    ()里用一个求Fibonacci数列的程序来说明CodeDOM是如何生成一些程序的基本语句的。现在写程序很少会直接写几个方法来让Main()从头调到尾的,总是要用几个类来封装封装的。

    CodeDOM里一个类的字段、属性、事件(讲到事件,委托总是逃不了的)、方法等又是如何来生成的呢?上次只讲到了类方法(CodeMemberMethod),在CodeTypeMember这个重量级的类下面还有很多没有涉及,这次用一个比较完整的类来讲余下的部分。

     

    开始部分的几下CodeCompileUnitCodeNamespaceCodeNamespaceImport都是一样的,就不多说了。

    声明一个名为DemoClass的类:

    CodeTypeDeclaration MyClass = new CodeTypeDeclaration("DemoClass");

    对一个Class来说除了名字外也没什么好设置的,一般情况下这样就行了。但有些定义了一些Attribute的要麻烦一点。要对MyClassCustomAttributes属性进行设置(不是MyClassAttributes这个属性,这个是设置可见性的)。

    对于Attribute的生成CodeDOM有专门的类来实现,就是CodeAttributeDeclaration。如要对DemoClass这个类加一个[Description("CodeDOM自动生成的一个类")]这样的Attribute可以这样写:

                    MyClass.CustomAttributes.Add(new CodeAttributeDeclaration("Description",new CodeAttributeArgument(

                     new CodePrimitiveExpression("CodeDOM自动生成的一个类"))));

    从上可以看到CodeAttributeDeclaration的构造函数,第一个参数是Attribute的名,第二个参数是Attribute的参数。对Description来说参数是“CodeDOM自动生成的一个类”这么一个字符串。当然不能直接用这个字符串来当构造函数的参数。对于Attribute的参数又有一个专门的类的――CodeAttributeArgument,真是麻烦。还要把字符串包成一个CodeExpression去当CodeAttributeArgument的构造函数的参数才算了结。(最后那个CodePrimitiveExpression在(三)里讲到过了,它返回一个原始的表达式,实际上就是把括号里的东西类型转换成一个CodeExpressoin)。

     

    (上面的长长的一句就是在写CodeDOM程序时构造函数连用的写法。当然你也可以不用这种new串联的写法,可以从最里层开始声明一个个的变量一句句的构造出来。上面一句就是分为四句了,不过这样写变量一多自己也要晕掉,所以一般不是太长的我还是喜欢连写,如果把代码格式编排一下一般写10new是没什么问题的。比较头痛的是在VS.NET中排好的格式到Word里会变掉)

     

    好,一个类声明好了,下面对类里的元素一个一个来说。

    先是字段Field,从它的类层次结构里能看出,这个肯定是用CodeMemberField来做的,如在类里声明

    private int myField;

    可以这样来写:

                    CodeMemberField myField = new CodeMemberField("System.Int32","myField");

                    //myField.Attributes = MemberAttributes.Private;

               MyClass.Members.Add(myField);

    它的构造函数,前一个参数是类型,后一个参数是字段名。前一个参数有很多种写法,这在(三)里说CodeParameterDeclarationExpression的时候提到过了(构造函数有(Type,string)(string,string)(CodeTypeReference,string)这三种写法),在CodeDOM里只要构造函数有关于类型的一般都有上述的Type,string,CodeTypeReference三种写法。

    Attribute对于字段来说默认是private。所以这里可以注释掉。

    一般地上面几点就够了,如果字段声明的同时要初始化的,只要设一下InitExpression就是了,这跟变量声明不太一样的地方是,它没有相应的构造函数,只能先new出来后,再设置相应的InitExpression属性。下面四句

                    CodeMemberField myArray = new CodeMemberField("System.Int32[]","myArray");

                    myArray.Attributes = MemberAttributes.Private;

                    myArray.InitExpression = new CodeArrayCreateExpression("System.Int32",10);

               MyClass.Members.Add(myArray);

    产生private int[] myArray = new int[10];

     

    数组比较的特别一点,声明的时候倒是容易,直接也在类型后加个“[]”就行了,就是初始化的时候麻烦一点,要用到数组创建表达式CodeArrayCreateExpression。它的用法参照一下对应的产生代码就明白了,构造函数都是大同小异的。

     

    字段声明完,接着要写构造函数了。构造函数就是一个比较特殊的类方法,CodeConstructor就是从CodeMemberMethod继承下来声明构造函数用的。除了名字不太一样,用法与CodeMemberMethodCodeEntryPointMethod差不多,这里就不详述了。

     

    下面是属性的写法:

                    CodeMemberProperty MyProperty = new CodeMemberProperty();

                    MyProperty.Name = "MyProperty";

                    MyProperty.Type = new CodeTypeReference("System.Int32");

                    MyProperty.Attributes = MemberAttributes.Public | MemberAttributes.Final;

                    MyProperty.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),"myField")));

                    MyProperty.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(),"myField"),

                         new CodePropertySetValueReferenceExpression()));

               MyClass.Members.Add(MyProperty);

    这么长长的一段出来

            public int MyProperty {

                get {

                    return this.myField;

                }

                set {

                    this.myField = value;

                }

            }

    这个CodeMemberProperty从上往下看,就是依次设置属性名、类型、可见性,以及getset方法的语句。这个GetStatements.Add()(或SetStatements.Add())里就随你加了,简单的属性设置就如上面一样,复杂的话就不断地依续再往里Add就是了。

    下面简单的讲一下GetSet里一些细节的东西。首先是return this.myField;这个是如何来的,上次讲Fibonacci数列时没讲到,返回值语句就是由CodeMethodReturnStatement产生的,要返回什么构造函数里就放什么,很简单。而this.myField就是类字段了,用CodeFieldReferenceExpression,不是上面的CodeMemberField,那个是声明类字段用的,这里是要引用类字段(跟变量声明与引用差不多)。同理CodePropertyReferenceExpression是就是用到类的属性时用了。在属性设置里“value”这个关键字会频繁的出现,在CodeDOM里对这个“value”也是有个专门的类的,就是CodePropertySetValueReferenceExpression了。比较特别的东西总是有个专门的类来表示,就象“this”就用CodeThisReferenceExpression来表示一样。

     

    在类的属性里有个比较特殊的属性就是索引器属性,设置索引器属性的写法与设置一般的属性基本一样,只是把属性名改为“Item”就行了。如:

    public int this[int index] {。。。。。略} 

    这么一个索引器属性由下述的语句产生:

                    CodeMemberProperty Pindex = new CodeMemberProperty();

                    Pindex.Comments.Add(new CodeCommentStatement("索引器属性"));

                    Pindex.Type = new CodeTypeReference("System.Int32");

                    Pindex.Name = "Item";//属性名设为Item,CodeDOM就当作是索引器属性处理

                    Pindex.Attributes = MemberAttributes.Public | MemberAttributes.Final;

               Pindex.Parameters.Add(new CodeParameterDeclarationExpression("System.Int32","index"));

    。。。。下略

     

    类属性的设置是够麻烦的,但最麻烦的要数类事件了,如果只是声明一下事件倒是简单得很,但讲到事件就不得不讲委托,这一下篇幅就长了。这留下次讲。

  • 相关阅读:
    验证码
    SQL给字段加上统一的某个字符
    科讯CMS V9标签清单
    需要重新启动计算机.必须重新启动计算机才能安装 SQL Server
    父页面iframe自动适应子页面的宽高度
    div随另一个div自动增高
    让图片在DIV中垂直居中
    nginx default server
    zabbix proxy 分布式监控
    openjdk tomcat 安装
  • 原文地址:https://www.cnblogs.com/lichdr/p/59620.html
Copyright © 2020-2023  润新知