使用C#和CodeDOM技术实现语言无关的Code Wizard

本文为原创,如需转载,请注明作者和出处,谢谢!

CodeDOM是.net
framework的一项重要的源代码生成技术。本文详细讨论了CodeDOM的原理以及如何利用CodeDOM技术实现一个与语言无关的Code Wizard。并给出了一个用C#语言实现的例子。

一、什么是CodeDom?

现在的程序规模越来越
大,虽然在计算发展的几十年间,产生了许多快捷、高效的编程语言和开发工具,如C#、Visual
Studio、java等。也产生了许多用以辅助软件设计、开发的思想和方法,如UML、OOP、Agile等。尽管利用这些技术和方法可以大大提高程序
编写的效率,但是仍可能有重复的编码工作。因此,现在出现了许多可以自动产生源代码或者目标文件的软件,即Code Wizards。
    一般这些Code
Wizards在生成源代码时都是通过设置模板文件,然后根据这些模板文件生成源代码。有很多Code Wizards只能生成固定的语言(如java、C#等)。虽然有一些Code
Wizards可
以生成多种语言,但也只是固定的几种。而且生成源代码部分都是显示地固定在程序中。这样非常不易扩展。如CodeSmith系统,这是一个非常不错的
Code
Wizard。它使用一个扩展名为cst的文件来设置模板。这个模板文件的格式类似于Asp.net。如果想生成C#源代码,必须要在其中显示地标明,并
且模板的固定部分要使用C#语言编写。如果这样的话,同样功能要生成不同语言的代码,如C#和VB.net。就要编写两个模板文件。这是非常不方便的。
    从以上的描述来看, Code
Wizard所
面临的一个重要问题就是如何使用一个模版文件来生成不同语言的源代码。幸好Microsoft提供了一种解决方案,这就是CodeDOM技术。
CodeDOM的全称是代码文档对象模型(Code Document Object Model)。整个CodeDOM就是一张对象图(object
graph)。它用这张图中的所有对象描述了面向对象语言中的几乎所有的语法现象,如类、接口、方法、属性等。CodeDOM通过对象模型对语言进行了抽象,然后利用具体语言所提供的生成源代码的机制来生成源代码,并可调用相应的编译器将源码生成*.dll或*.exe。从而可以达到与语言无关的目的。图1描述了使用CodeDOM生成和编译源代码的过程。

图1 CodeDom生成和编译源代码的过程

从上图可以看出,CodeWizard只使用CodeDOM对语言进行抽象,然后通过CodeDomProvider生成源代码。最后通过编译器生成中间语言。下面将详细讨论如何利用CodeDOM来实现CodeWizard。

二、实现CodeWizard

下面要实现的这个
CodeWizard非常简单。其功能主要是将一个数据表映射成一个类。这个类提供了Add和Save方法以及和数据表的每个字段相对应的属性。使用这个
类可以向数据表添加记录。为了便于描述,将这个数据表保存成xml文件格式。每条记录为一个item结点,每一个字段为这个结点的一个属性。表名为这个
xml文件的根结点名称。这个xml文件的格式如下所示:

<MyTable>    
    <item id = "01 " name = "Bill "/>
    <item id = "02" name = "Mike" />
</MyTable>

这个CodeWizard通过一个模板文件来定义数据表的结构。模板文件的格式如下:

<MyTable>
    <id type = "System.Int32"/>
    <name type = "System.String"/>
</MyTable>

 

其中type为字段的类
型,它的值是在.net
framework中的System中定义的简单类型,如System.Int32、System.String、System.Char等。下面就详细
讨论如何利用这个模板文件和CodeDOM技术来生成C#和VB.net的源代码。

三、CodeDOM的结构

CodeDOM由两部分组成:

1. 用于描述抽象代码结构的一组类。其中CodeCompileUnit类是这些类的根。代表一个源码文件(如C#的*.cs和VB.net的*.vb)。在使用CodeDOM时,必须先建立一个CodeCompileUnit类的对象,然后在这个对象中加入必要的namespace、class等面向对象元素。

用于生成和编译源代码的类。这个类必须从CodeDomProvider类继承。每种.net
framework

所支持的语言都有自己的CodeDomProvider类。如在C#中的CodeDomProvider类叫CSharpCodeProvider,而在VB.net中叫VBCodeProvider。

四、数据表类的定义

要用CodeDOM定义一个类需要三步:

1. 建立一个CodeCompileUnit对象。这个类相当于一个源码文件。

2. 建立一个CodeNamespace对象。理论上在.net
framework上运行的程序语言,如C#、VB.net

等,可以没有namespace。但在CodeDOM中必须使用这个类,如果不想要namespace,可以将namespace的名字设为 null或空串。

建立一个CodeTypeDeclaration对象。这个类可以建立Class和Interface两种Type。在

这个例子中只建立Class。如果想建立Interface,只需将IsInterface属性设为true即可。

主要的实现代码如下:

    private CodeCompileUnit m_CodeCompileUnit;
    private CodeNamespace m_CodeNameSpace;
    private CodeTypeDeclaration m_Class;
    private void InitCodeDom()
    {
        m_CodeCompileUnit = new CodeCompileUnit();
        m_CodeNameSpace = new CodeNamespace("xml.tables"); 
        m_CodeCompileUnit.Namespaces.Add(m_CodeNameSpace);
        m_Class = new CodeTypeDeclaration(m_ClassName);
        m_CodeNameSpace.Types.Add(m_Class);
}

 


中namespace的名子是“xml.tables”。在建立完namespace后,将其加入到m_CodeCompileUnit的
Namespaces集合中。m_ClassName是一个String变量,它的值就是数据表的表名。最后将所建立的类加入到namespace的
Types集合中。在产生完类后。需要在这个类中加入四部分内容,它们分别是:全局变量、属性、构造函数和方法(Add和Save方法)。下面就分别讨论
它们的实现过程。

五、全局变量的生成

这个数据表类中有四种全局变量:用于操作xml文件的类型为XmlDocument的变量、用于保存数据表文件名的变量、用于确定是否为加入状态的Boolean型变量、以及用于保存每个字段值的变量组。具体实现代码如下:

private void GenerateFields()
{
    // 产生 "private XmlDocument m_xml = new XmlDocument();"  
    CodeMemberField xml = new CodeMemberField("System.Xml.XmlDocument", "m_xml");
    CodeObjectCreateExpression createxml = new CodeObjectCreateExpression("System.Xml.XmlDocument");
    xml.InitExpression = createxml;
    m_Class.Members.Add(xml);
    // 产生 "private String m_XmlFile;"  
    CodeMemberField xmlfile = new CodeMemberField("System.String", "m_XmlFile");
    m_Class.Members.Add(xmlfile);
// 根据模板文件产生保存字段值的变量
   
String fieldname = "", fieldtype = "";
    foreach (XmlNode xn in m_Xml.DocumentElement.ChildNodes)
    {
         fieldname = "m_" + xn.Name;
         fieldtype = xn.Attributes["type"].Value;
         CodeMemberField field = new CodeMemberField(fieldtype, fieldname);
         m_Class.Members.Add(field);
    }
    // 产生 "private bool m_AddFlag;" 
    CodeMemberField addflag = new CodeMemberField("System.Boolean", "m_AddFlag");
    m_Class.Members.Add(addflag);
}

 

在以上代码中每段程序上方的注释是它们所生成的C#源代码。在输入这段代码之前,需要引入两个namespace。

using System.CodeDom;
using System.CodeDom.Compiler;

 

五、属性的生成

    在数据表类中每个属性代表数据表的一个字段,名子就是字段名。这些属性和保存字段的全局变量一一对应。下面是具体的实现代码:

private void GenerateProperties()
{
    String fieldname = "", fieldtype = "";
    foreach (XmlNode xn in m_Xml.DocumentElement.ChildNodes)
    {
        fieldname = xn.Name;
        fieldtype = xn.Attributes["type"].Value;
        CodeMemberProperty property = new CodeMemberProperty();
        property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
        property.Name = fieldname;
        property.Type = new CodeTypeReference(fieldtype);
        property.HasGet = true;
        property.HasSet = true;
        CodeVariableReferenceExpression field = new CodeVariableReferenceExpression("m_" + fieldname);
        // 产生 return m_property
        CodeMethodReturnStatement propertyReturn = new CodeMethodReturnStatement(field);
        property.GetStatements.Add(propertyReturn);
        // 产生 m_property = value;
        CodeAssignStatement propertyAssignment = new CodeAssignStatement(field,
        new CodePropertySetValueReferenceExpression());
        property.SetStatements.Add(propertyAssignment);
        m_Class.Members.Add(property);
    }
}

 

这些生成的属性是可读写的。这就需要将HasGet和HasSet两个属性设为true,然后分别将get和set方法中的语句分别加到GetStatements和SetStatements中。

六、构造函数的生成

    构造函数的主要工作是打开数据表。如果数据表不存在,就创建这个数据表文件。在编写代码之前,需要先定义三个全局变量。因为这三个全局变量在程序中会多次用到。它们的类型都是CodeVariableReferenceExpression。这个类型变量其实在生成源码中的作用就是对某一个变量的引用。具体的实现代码如下:

private CodeVariableReferenceExpression m_XmlFileExpression;
private CodeVariableReferenceExpression m_XmlExpression;
private CodeVariableReferenceExpression m_AddFlagExpression;        
private void InitVariants()
{
m_XmlFileExpression = new CodeVariableReferenceExpression("m_XmlFile");
    m_XmlExpression = new CodeVariableReferenceExpression("m_xml");
    m_AddFlagExpression = new CodeVariableReferenceExpression("m_AddFlag");
}

 

下面是生成构造函数的源代码:

private void GenerateConstructor()
{
    // 定义构造函数
    CodeConstructor constructor = new CodeConstructor();
    constructor.Parameters.Add(new CodeParameterDeclarationExpression("System.String", "xmlFile"));
    constructor.Attributes = MemberAttributes.Public;
    // 产生 "m_XmlFile = xmlFile;" 
    CodeAssignStatement assignXmlFile = new CodeAssignStatement(m_XmlFileExpression,
    new CodeVariableReferenceExpression("xmlFile"));
    // 产生 "m_xml.LoadXml("…");"
    CodeMethodInvokeExpression invokeLoadXml = new CodeMethodInvokeExpression(m_XmlExpression, "LoadXml",
   new CodePrimitiveExpression("<?xml version=/"1.0/" encoding=/"gb2312/" ?><" + m_Xml.DocumentElement.Name
   + "></" + m_Xml.DocumentElement.Name + ">"));
    // 产生 "m_xml.Save(m_XmlFile);"
    CodeMethodInvokeExpression invokeSave = new CodeMethodInvokeExpression(m_XmlExpression, "Save",
    m_XmlFileExpression);
    CodeStatementCollection statements = new CodeStatementCollection();
    statements.Add(invokeLoadXml);
    statements.Add(invokeSave);
    // 产生if语句:  "if (System.IO.File.Exists(m_XmlFile))  else  "
    CodeConditionStatement ifStatement = new CodeConditionStatement(new CodeMethodInvokeExpression(
   new CodeVariableReferenceExpression("System.IO.File"), "Exists", m_XmlFileExpression), new CodeStatement[] { } ,
   new CodeStatement[] { statements[0], statements[1] });
    // 产生 "m_xml.Load(m_XmlFile);"
    CodeMethodInvokeExpression invokeLoad = new CodeMethodInvokeExpression(m_XmlExpression, "Load",
     m_XmlFileExpression);
    // 产生 "m_AddFlag = false;"
    CodeAssignStatement assignAddFalse = new CodeAssignStatement(m_AddFlagExpression,
    new CodePrimitiveExpression(false));
    constructor.Statements.Add(assignXmlFile);
    constructor.Statements.Add(ifStatement);
    constructor.Statements.Add(invokeLoad);
    constructor.Statements.Add(assignAddFalse);
     m_Class.Members.Add(constructor);
}


七、Add和Save方法生成

Add方法只有一条语句,功能是将m_AddFlag设为true,以使数据表类处于加入状态。Save方法比较复杂。它的功能是当m_AddFlag为true时在数据表文件的最后加入一条记录,并保存。具体实现代码如下:

private void GenerateMethods()
{
CodeTypeReference voidReference = new CodeTypeReference("System.void");
    //产生Add方法
    CodeMemberMethod add = new CodeMemberMethod();
    add.ReturnType = voidReference;
    add.Name = "add";
    add.Attributes = MemberAttributes.Public | MemberAttributes.Final;
    CodeAssignStatement assignAddTrue = new CodeAssignStatement(m_AddFlagExpression,
    new CodePrimitiveExpression(true));
    add.Statements.Add(assignAddTrue);
    m_Class.Members.Add(add);
    //产生Save方法
    CodeMemberMethod save = new CodeMemberMethod();
   save.ReturnType = voidReference;
   save.Name = "save";
   save.Attributes = MemberAttributes.Public | MemberAttributes.Final;
   System.Collections.Generic.List<CodeStatement> ifStatements =
   new System.Collections.Generic.List<CodeStatement>();
   //产生 "XmlNode xn = m_xml.CreateNode(XmlNodeType.Element, "item", "");"
  CodeVariableDeclarationStatement xmlNode = new CodeVariableDeclarationStatement("System.Xml.XmlNode", "xn");
   CodeMethodInvokeExpression createNode = new CodeMethodInvokeExpression(m_XmlExpression, "CreateNode", 
  new CodeExpression[] {new CodeVariableReferenceExpression("System.Xml.XmlNodeType.Element"),
  new CodePrimitiveExpression("item"),
  new CodePrimitiveExpression("") });
   xmlNode.InitExpression = createNode;
   ifStatements.Add(xmlNode);
   //产生 "XmlAttribute xa = null; "
   CodeVariableDeclarationStatement xmlAttr = new CodeVariableDeclarationStatement("System.Xml.XmlAttribute", "xa");
   xmlAttr.InitExpression = new CodePrimitiveExpression(null);
   ifStatements.Add(xmlAttr);
//产生字段属性
   CodeStatementCollection statements = new CodeStatementCollection();
   foreach (XmlNode xn in m_Xml.DocumentElement.ChildNodes)
   {
   CodeMethodInvokeExpression createAttribute = new CodeMethodInvokeExpression(m_XmlExpression,
           "CreateAttribute", new CodePrimitiveExpression(xn.Name));
       CodeAssignStatement assignxa = new CodeAssignStatement(
        new CodeVariableReferenceExpression("xa"), createAttribute);
       CodeMethodInvokeExpression invokeToString = new CodeMethodInvokeExpression(
        new CodeVariableReferenceExpression("m_" + xn.Name), "ToString");
       CodeAssignStatement assignValue = new CodeAssignStatement(
      new CodeVariableReferenceExpression("xa.Value"), invokeToString);
       CodeMethodInvokeExpression invokeAppend = new CodeMethodInvokeExpression(
      new CodeVariableReferenceExpression("xn.Attributes"),
       "Append", new CodeVariableReferenceExpression("xa"));                
       statements.Add(invokeAppend);
       ifStatements.Add(assignxa);
       ifStatements.Add(assignValue);
       ifStatements.Add(statements[0]);
   }
   // 产生 "m_xml.DocumentElement.AppendChild(xn);"
   CodeMethodInvokeExpression invokeAppendChild = new CodeMethodInvokeExpression(new
  CodeVariableReferenceExpression("m_xml.DocumentElement"), "AppendChild",
   new CodeVariableReferenceExpression("xn"));
   statements.Clear();
   statements.Add(invokeAppendChild);
    ifStatements.Add(statements[0]);
    // 产生 "m_xml.Save(m_XmlFile);"
    CodeMethodInvokeExpression invokeSave = new CodeMethodInvokeExpression(m_XmlExpression,
   "Save", m_XmlFileExpression);
    statements.Clear();
    statements.Add(invokeSave);
    ifStatements.Add(statements[0]);
    // 产生 "m_AddFlag = false;" 
    CodeAssignStatement assignAddFalse = new CodeAssignStatement(m_AddFlagExpression,
    new CodePrimitiveExpression(false));
   
ifStatements.Add(assignAddFalse);
// 产生if语句: "if (m_AddFlag)"
    CodeConditionStatement ifStatement = new CodeConditionStatement(m_AddFlagExpression,
    ifStatements.ToArray());
    save.Statements.Add(ifStatement);
    m_Class.Members.Add(save);
}

 

八、生成源代码

生成具体语言的源代码需要一个从CodeDomProvider继承的类。对于C#而言是CSharpCodeProvider类。实现代码如下:

using Microsoft.CSharp;
public void SaveCSharp(String filename)
{
IndentedTextWriter tw = new IndentedTextWriter(new StreamWriter(filename, false), "    ");
    CodeDomProvider provide = new CSharpCodeProvider(); 
    provide.GenerateCodeFromCompileUnit(m_CodeCompileUnit, tw, new CodeGeneratorOptions());
    tw.Close();
}

 

在使用CSharpCodeProvider类时需要用到m_CodeCompileUnit这个全局变量。这样可产生一个*.cs文件。以上代码中的IndentedTextWriter类是建立一个文件的Writer,用于向这个文件中输出源代码。但和其它的Writer不同的是它的输出是缩进的(以四个空格进行缩进)。如是想生成VB.net的代码,只需将CSharpCodeProvider改为VBCodeProvider即可。

九、编译源代码


现在为止,这个数据表类的源代码已经全部生成了。你可以将这个源文件直接加入到自己的工程中。或者直接将其编译成*.dll文件,然后在程序中调用。如果
想编译,可以直接调用指定语言的编译器(如C#中的csc.exe)。但这样不是太方便。在CodeDOM中提供了一种机制,可以在程序中通过
CodeDomProvider直接调用指定语言的编译器。下面是编译C#源程序的一个例子。

 

public void CompileCSharp(String sourcefile, String targetFile)
{
CompilerParameters cp = new CompilerParameters(new String[] { "System.Xml.dll" },  targetFile, false);
   CodeDomProvider provider = new CSharpCodeProvider();
   cp.GenerateExecutable = false;
   // 调用编译器
   CompilerResults cr = provider.CompileAssemblyFromFile(cp, sourcefile);
   if (cr.Errors.Count > 0)
   {
       // 显示编译错误
       foreach (CompilerError ce in cr.Errors)
           System.Windows.Forms.MessageBox.Show(ce.ToString());
   }
}

 

对于以上代码有两点说明:

  1. 使用CodeDomProvider调用编译器时也需要传递相应的参数,如在本例中将System.Xml.dll

作为一个参数,表示目标文件需要调用这个dll中的资源。

  1. 在调用编译器后,如果出现错误,可使用cr.Errors获得错误信息。

十、结束语

我花了一个晚上的时间实现了这个简单的例子,并用C#2.0调试通过,只是为了抛砖引玉。自动生成源代码有很多的方法,但使用CodeDom生成源代码会有更大的灵活性,主要表现在以下三个方面:

1.    
语言无关。即只要是.net framework所支持的语言,并且这种语言提供了CodeDomProvider。

就可以生成这种语言的源代码。

2.    
如果所生成的语言是测试版或要将这种语言升级到下一个版本,也可以考虑使用CodeDOM。

因为当这种语言的语法有所变化时,CodeDomProvider也会随之升级。因此,使用CodeDOM的Code Wizards也会随着CodeDOM而升级,这样就不必修改Code Wizards的源代码了。

3.    
如果所生成的一种语言是你所不熟悉的,如果不使用CodeDOM,必须要熟悉这种语言的语

法,才能生成它的源代码。而使用CodeDOM却可以避免这一点。因为CodeDOM是使用抽象的object graph来描述语言的。而语言的具体语法是由CodeDomProvider所决定的。

其实CodeDOM不仅可以用在Code
Wizards上,也可以用在许多其它地方,如可以生成Web

Services的客户端代理(Client Proxies),或根据UML图生成类的构架代码。总之,使用CodeDom可以大大降低和语言的偶合度,并且很容易维护和升级系统。

时间: 2024-10-26 02:54:42

使用C#和CodeDOM技术实现语言无关的Code Wizard的相关文章

数据挖掘-请问下,现在网上那些淘宝数据分析工具是用什么技术或语言做的?

问题描述 请问下,现在网上那些淘宝数据分析工具是用什么技术或语言做的? 主要是数据采集这一块,有没有大神在这一块的内容有所涉及.百度了数据挖掘,但是里面说的东西太虚,太泛.数据采集,数据挖掘我就知道有个网络爬虫可以做,除此之外还有什么工具,技术可以选择吗? 解决方案 一般来说用python比较好,因为诸如数理统计.机器学习.聚类分析.回归分析等的库很全. 解决方案二: 淘宝数据分析

微软借互联网挖掘技术开发语言学习工具

导读:国外媒体今天撰文称,微软通过互联网数据挖掘技术开发了一款名为英库的语言学习工具,并有望借此为必应吸引更多用户,获得更多广告收入. 以下为文章全文: 挖掘数据 微软位于北京的研究人员正在使用从互联网中挖掘的数据来改进在线汉英词典以及语言练习服务.该技术有朝一日将被用在一些类似的工具上,使得所有语言学习者都能够使用. 英库(www.engkoo.com)是"英语"和"仓库"的合成词.该产品的核心是翻译数据.这些数据是微软在一些获得出版商授权的词典中提取出来的.除此

字符编辑技术C语言实现

#include<string.h> #include<ctype.h> #include<stdio.h> /*插入函数 ccode待插入的字符 anystring被插入的字符串 spos插入到字符串的位置*/ void cinsert(char ccode,char *anystring,int spos) ; /*删除函数 anystring被删除的字符串 spos删除第几个字符*/ void cdelete(char *anystring,int spos) ;

一起谈.NET技术,以 .NET 创建 Code 39 条码图片 供水晶报表打印

教导如何用 C# 创建 Code 39 编码的「条码 (barcode)」图片,以供 ASP.NET + Crystal Reports 水晶报表呈现和打印此条码.本帖提供 ASP.NET 3.5 示例下载. 本帖的示例下载点:http://files.cnblogs.com/WizardWu/100914.zip 执行本示例,需要 SQL Server 的 Northwind 数据库,以及 VS 2008 或 IIS,另还需要 Crystal Reports 2008 标准版 (SAP 公司的

多语言网站开发技术分析

语言是信息传播的主要障碍. 多语言网站,顾名思义就是能够以多种语言(而不是单种语言)为用户提供信息服务,让使用不同语言的用户都能够从同个网站获得内容相同的信息. 多语言网站实现方案 1,静态:就是为每种语言分别准备一套页面文件,要么通过文件后缀名来区分不同语言,要么通过子目录来区分不同语言. 例如对于首页文件index_en.htm提供英语界面,index_gb.htm提供简体中文界面,index_big.htm提供繁体中文界面,或者是en/index.htm提供英语界面,gb/index.ht

《C语言接口与实现:创建可重用软件的技术》一导读

前言 C语言接口与实现:创建可重用软件的技术 如今的程序员忙于应付大量关于API(Application Programming Interface)的信息.但是,大多数程序员都会在其所写的几乎每一个应用程序中使用API并实现API的库,只有少数程序员会创建或发布新的能广泛应用的API.事实上,程序员似乎更喜欢使用自己搞的东西,而不愿意查找能满足他们要求的程序库,这或许是因为写特定应用程序的代码要比设计可广泛使用的API容易. 不好意思,我也未能免俗:lcc(我和Chris Fraser为ANS

多语言网站开发 不完全技术分析收录

语言是信息传播的主要障碍.多语言网站,顾名思义就是能够以多种语言(而不是单种语言)为用户提供信息服务,让使用不同语言的用户都能够从同个网站获得内容相同的信息.多语言网站实现方案 1,静态:就是为每种语言分别准备一套页面文件,要么通过文件后缀名来区分不同语言,要么通过子目录来区分不同语言.例如对于首页文件index_en.htm提供英语界面,index_gb.htm提供简体中文界面,index_big.htm提供繁体中文界面,或者是en/index.htm提供英语界面,gb/index.htm提供

《R语言游戏数据分析与挖掘》一第3章 R语言绘图重要技术

第3章 R语言绘图重要技术R语言除了拥有良好的数据处理和分析能力外,对于展现数据也有极其灵活和强大的应用.由于用图形表达分析结果往往更直观和简单,所以对于优秀的分析报告而言,将数据结果以适当的图形方式展示后,其沟通效果和说服力会更佳.本章将介绍如何向一幅简单的图形中添加元素,以得到更有用和更吸引人的图形,以及绘制各种类型图形的函数.

CodeDom系列-开篇HelloWord

最近在自己实践一个异常扑捉设计,在模块中我觉得该给用户提供的是代码生成工具,而不是怎么去做,再自己去写代码.现在代码模板生成的有很多 但我选择了用微软的CODEDOM技术来实现,由于比较熟悉,以及感觉我将只用在.NET平台是已经够强大了.最近也总想写点博客,但是不知道写些什么,所以就准备写个CODEDOM的系列.仅是开篇,就写个简单的HelloWord程序吧. CODEDOM在.NET Framework SDK文档里是这么讲述的: .NET Framework 中包含一个名为"代码文档对象模型