动态生成与编译(六)――测试一下CodeDOM生成的类 这么简单的一个类,其实直接让它生成类代码看一下也就知道行不行了。但既然做就做到底,把测试用的代码也一并用CodeDOM来生成算了,而且CodeDOM里还有几个类也要随便说一下。 先看生成后的代码(直接在原namespace里新做了一个类): public class TestClass { public static void Main() { DemoClass a = new DemoClass(); DemoClass b = new DemoClass(123); Console.WriteLine("MyConst = {0}", DemoClass.MyConst); Console.WriteLine("a.MyProperty = {0}", a.MyProperty); Console.WriteLine("b.MyProperty = {0}", b.MyProperty); a.MyMethod(); // 附加委托 a.MyEvent += new myEventHandler(TestClass.MyHandler); a.MyMethod(); // 移除委托 a.MyEvent -= new myEventHandler(TestClass.MyHandler); a.MyMethod(); a[5] = (a[3] = 11); for (int i = 0; (i < 10); i = (i + 1)) { Console.WriteLine("a[{0}] = {1}", i, a[i]); } Console.Read(); } static void MyHandler(object sender, myEventArgs e) { Console.WriteLine(e.Dt.ToString()); } } 现在虽然看CodeDOM程序时虽能在脑海里浮现生成的相应代码了,但CodeDOM程序还写得不熟,如果不对着生成的代码来写CodeDOM程序还是有点累。现在一般都要先写好目标代码的大致形状,再反过来写CodeDOM程序,现在也照上面生成的代码来分析要写的CodeDOM程序。 CodeTypeDeclaration TestClass = new CodeTypeDeclaration("TestClass"); CodeEntryPointMethod Start = new CodeEntryPointMethod(); 开始这两句总归是少了的,下面两句声明变量a、b的只讲一句(第二句稍复杂,就讲它了),变量声明的以前讲到过了。如果不初始化变量倒是简单: CodeVariableDeclarationStatement classb = new CodeVariableDeclarationStatement("DemoClass","b") 就OK,后面那个new DemoClass(123)一加就烦了,要设置classb的InitExpression(或者在构造函数里传第三个参数,效果一样的)。一看New什么什么的,下面要用上类的构造函数了,在CodeDOM里创建一个类的新实例的表达式用 public CodeObjectCreateExpression(
string createType, params CodeExpression[] parameters );
第一个参数是要创建的类型,第二个参数是构造函数的参数,当然没有参数就省略了,上面的CodeDOM程序加上 classb.InitExpression = new CodeObjectCreateExpression("DemoClass",new odePrimitiveExpression(123)) 后就完成第二句变量b的声明了。 下面三句输出控制台的语句就是方法调用,这个是很熟的了,一开始就用过的,当然是用CodeMethodInvokeExpression了。它的参数的DemoClass.MyConst与 a.MyProperty这两个分别就是类的字段、属性依次用CodeFieldReferenceExpression、CodePropertyReferenceExpression也很简单的。只看一下第二句的写法: new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("Console"),"WriteLine", new CodeExpression[] {new CodePrimitiveExpression("a.MyProperty = {0}"),new CodePropertyReferenceExpression(new CodeVariableReferenceExpression("a"),"MyProperty")}); (我喜欢这种长长的写法,不用去声明一串的变量,这样一眼就能看出来产生的代码是什么。只要输的时候左括号、右括号先对好就不太会出错) 接下来几句是看事件的效果的,先调一下MyMethod,加委托后再调一次,移除委托后最后调一次。主要是附加与移除委托的这两句。 先看new myEventHandler(TestClass.MyHandler)这一句是如何产生的,又是一个new,不过它不是类实例的创建,当然用CodeObjectCreateExpression来写,最后的代码效果是一样的,不过还是不要那样写的好。创建委托用 public CodeDelegateCreateExpression(
CodeTypeReference delegateType, CodeExpression targetObject, string methodName ); 所以CodeDelegateCreateExpression delecra = new CodeDelegateCreateExpression(。。。略); 后面的委托new好了,下面就是加上去的事: CodeAttachEventStatement attevent = new CodeAttachEventStatement( new CodeVariableReferenceExpression("a"),"MyEvent",delecra); 是附加,那 CodeRemoveEventStatement removevent = new CodeRemoveEventStatement( new CodeVariableReferenceExpression("a"),"MyEvent",delecra); 就是移除了。 最后看一下类的索引器属性。a[5] = (a[3] = 11);这一句连续赋值的,先看a[5]是如何来的,这实际就是数组里的东西是如何取的问题啦,CodeDOM有一个CodeArrayIndexerExpression刚好可以派上用场。new CodeArrayIndexerExpression(new CodeVariableReferenceExpression("a"),new CodePrimitiveExpression(5))就会产生a[5],很明显前一个参数是索引器的对象,后一个参数是具体的索引数。 下面的连续赋值, CodeDOM生成a[5]=(a[3]=11)这样看起来还是比较的清楚。它就是一个CodeAssignStatement,左项是a[5],而右项(a[3]=11)就是一个运算表达式CodeBinaryOperatorExpression,只不过它的运算符是赋值运算符而已。其实生成(a[5]=a[3])=11也是一样的。 不过上面的这两种写法要写的CodeDOM代码复杂得要命,还不如分成两句赋值语句写来得省事。 后面的一个循环没什么,最简单基本的东西,在(三)里提过了,略过。 下面那个供委托用的“MyHandler”方法只有一句方法调用,也没什么新东西。 用上面的CodeDOM程序生成的代码文件编译产生EXE文件,双击执行,在控制台输出如下: Instance constructor1 Instance constructor2 MyConst = 12 a.MyProperty = 0 b.MyProperty = 123 DemoClass.MyMethod DemoClass.MyMethod Invokes MyEvent 2004-11-04 21:20:50 -------这里当然与程序执行时间有关 DemoClass.MyMethod a[0] = 0 a[1] = 0 a[2] = 0 a[3] = 11 a[4] = 0 a[5] = 11 a[6] = 0 a[7] = 0 a[8] = 0 a[9] = 0 看来CodeDOM生成的那个类,及后面用来测试它的代码正常的工作。 |
|