Type t = listBox1.GetType(); object o = t.GetProperty("Items").GetValue(listBox1,null);
MethodInfo mi = o.GetType().GetMethod("Clear"); mi.Invoke(o,null);
<----------------------------------------------------------------------> Type t = FindType("System.Windows.Forms.TextBox");
ConstructorInfo ci = t.GetConstructor(new Type[]{}); object o = ci.Invoke(null);
this.Controls.Add((Control)o); <----------------------------------------------------------------------> Type t = listBox1.GetType(); object o = t.GetProperty("Items").GetValue(listBox1,null);
o.GetType().InvokeMember("Clear",BindingFlags.InvokeMethod,null,o,null); |
此技术是.NET Framework中用来产生程序代码的基础建设,它以对象化的方式仿真出程序代码的逻辑,最后交由特定的Code Provider对象来产生出源程序代码。由于CodeDOM是高度对象化后的程序逻辑对象,因此由此技术所产生的程序代码会随着使用Code Provider对象类型而改变,也就是说当设计人员将CodeDOM对象交给CSharpCodeProvider对象产生程序代码时,其产生的将是C#的源代码,当Code Provider是VBCodeProvider时,其产生的就是VB.NET的程序代码。CodeDOM技术应用于许多地方,例如IDE Code Serializer、ASP.NET Just-In-Time Compiler等中都有其身影存在。不过CodeDOM拥有庞大的对象群,常让设计人员有种不知由何着手的感觉,但是一旦了解了其中几个对象后,你就会发现这些对象的用法是相当直观的。
2-4-1 CodeCompileUnit,CodeNamespace
CodeCompileUnit是CodeDOM中的根容器型对象,其内可以加入CodeNamespace对象来产生namespace语句,程序2-23的程序代码片段示范了此用法。
程序2-23 运用CodeCompileUnit对象的范例
using System.IO; using System.CodeDom; using System.CodeDom.Compiler; using Microsoft.CSharp;
..............
CodeCompileUnit unit = new CodeCompileUnit();
CodeDomProvider provider = new CSharpCodeProvider(); StringWriter sw = new StringWriter(); ICodeGenerator generator = provider.CreateGenerator();
unit.Namespaces.Add(new CodeNamespace("MyNamespace"));
generator.GenerateCodeFromCompileUnit(unit,sw, new CodeGeneratorOptions()); |
程序2-23会产生程序2-24的C#源代码。
程序2-24 由程序2-23所产生的C#源代码
namespace MyNamespace { } |
2-4-2 CodeNamespaceImport、CodeTypeDeclaration
CodeNamespaceImport对象用来产生using xxx类引用Namespace的程序代码,目前CodeDOM的实现只允许用户经由CodeNamespace对象来加入CodeNamespaceImport对象。CodeTypeDeclaration则是用来产生声明类型的对象,它可以处理类、枚举、结构、接口,与CodeNamespaceImport对象相同,此对象也只允许经由CodeNamespace对象来加入,程序2-25的程序代码片段示范这两个对象的用法。
程序2-25 运用CodeNamespaceImport、CodeTypeDeclaration对象的范例
CodeNamespace cNS = new CodeNamespace("MyNamespace"); cNS.Imports.Add(new CodeNamespaceImport("System")); CodeTypeDeclaration cClass = new CodeTypeDeclaration("MyClass"); CodeTypeDeclaration cInterface= cInterface.IsInterface = true; cNS.Types.Add(cClass); cNS.Types.Add(cInterface); unit.Namespaces.Add(cNS); <-----------------------------------------------------------> //2-25所产生的源代码 namespace MyNamespace { using System; public class MyClass { }
public interface IMyInterface { } } |
CodeTypeDeclaration对象允许用户指定产生类型的修饰符,2-26的程序代码片段示范如何产生一个抽象类。
程序2-26 运用CodeTypeDeclaration产生一个抽象类的范例
using refl = System.Reflection; ...... CodeTypeDeclaration cClass = new CodeTypeDeclaration("MyClass"); cClass.TypeAttributes = refl.TypeAttributes.Abstract | |
读者可于On-Line Help查到System.Reflection.TypeAttributes其他的可能值。另外CodeTypeDeclaration对象也允许指定基础类,设计者可经由BaseType属性来加入基础类,如程序2-27所示。
程序2-27 为CodeTypeDeclaration指定基础类
cClass.BaseTypes.Add(new CodeTypeReference(typeof( |
2-4-3 CodeMemberField、CodeMemberMethod、
CodeMemberProperty、CodeMemberEvent
这四个对象分别可以产生成员函数、成员变量、成员事件、成员属性四种声明型程序代码,它们必须经由CodeTypeDeclaration.Members对象来加入,见程序2-28。
程序2-28 使用CodeMemberField等四种对象的范例
CodeTypeDeclaration cClass = new CodeTypeDeclaration("MyClass"); CodeMemberField cField = new CodeMemberField(typeof(int),"m_int"); CodeMemberMethod cMethod = new CodeMemberMethod(); cMethod.Name = "TestMethod"; CodeMemberProperty cProperty = new CodeMemberProperty(); cProperty.Name = "TestProperty"; cProperty.HasGet = true; cProperty.Type = new CodeTypeReference(typeof(int)); cProperty.GetStatements.Add(new CodeMethodReturnStatement( new CodeFieldReferenceExpression( new CodeBaseReferenceExpression(),"m_int"))); cClass.Members.Add(cField); cClass.Members.Add(cProperty); cClass.Members.Add(cMethod); |
先由CodeMemberMethod对象谈起,一个成员函数可以拥有参数及返回值,范例程序中并未预定义TestMethod函数的返回值及参数信息,这会产生一个无返回值与参数的函数,如用户须预定义这些信息时,必须经由其ReturnType及Parameter属性来设定,如程序2-29所示。
程序2-29 为CodeMemberMethod指定ReturnType及Parameter
cMethod.ReturnType = new CodeTypeReference(typeof(int)); cMethod.Parameters.Add( new CodeParameterDeclarationExpression(typeof(int),"int1")); cMethod.Statements.Add(new CodeMethodReturnStatement( |
前两行用来预定义函数的返回值及参数,第三行是预定义函数内的程序代码,此处使用CodeMethodReturnStatement对象来预定义一个return语句,CodePrimitiveExpression对象则预定义一个内建类型的值,此处是数值0。CodeMemberProperty是预定义成员属性的对象,它有几个重要的设定,HasGet、HasSet代表这个属性是否拥有get或set区段,当设定了其中一个为True之后,连带必须在GetStatement或是SetStatement属性加入语句,范例中在GetStatement属性内加入了一个CodeMethodReturnStatement对象,并于其中加入了一个CodeFieldReferenceExpression对象,这是用来预定义成员变量引用的语句,于其内又预定义了CodeBaseReferenceExpression对象,这会产生引用至base的语句,整个范例产生的结果见程序2-30。
程序2-30 程序2-29所产生的程序代码
namespace MyNamespace { using System; public class MyClass { private int m_int; private int TestProperty { get { return base.m_int; } } private int TestMethod(int int1) { return 0; } } } |