zoukankan      html  css  js  c++  java
  • 动态生成与编译(四)用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"));

    。。。。下略

     

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

  • 相关阅读:
    RecyclerView 数据刷新的几种方式 局部刷新 notify MD
    【图片】批量获取几万张图片
    RV BaseRecyclerViewAdapterHelper 总结 MD
    RecyclerView.ItemDecoration 间隔线
    Kotlin【简介】Android开发 配置 扩展
    Kotlin 特性 语法糖 优势 扩展 高阶 MD
    一个十分简洁实用的MD风格的UI主框架
    折叠伸缩工具栏 CollapsingToolbarLayout
    FloatingActionButton FAB 悬浮按钮
    Glide Picasso Fresco UIL 图片框架 缓存 MD
  • 原文地址:https://www.cnblogs.com/lichdr/p/59620.html
Copyright © 2011-2022 走看看