Net有道

紫冠道人的求道历程

导航

<2004年10月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

与我联系

搜索

 

常用链接

留言簿(21)

我参与的团队

随笔分类

随笔档案

文章分类

文章档案

Program

程序之外的生活

我的阅读BLOG

积分与排名

最新评论

  • 1. re: 动态生成与编译(九)----CodeDOM的局限
  • @vivisimo
    没有这种功能,反正以前微软只提供了一个没有任何实现的空的接口在那。
    不知新版本后有什么改进。
  • --lichdr
  • 2. re: 动态生成与编译(九)----CodeDOM的局限
  • 请问要编一个对C#语法程序的词法分析器,codeDom中有没有什么方法和类封装了这样的功能,可以被直接使用的?或者C#中有没有其他这样的类或方法?词法分析程序中要提取程序的单词,并对单词的种类进行识别...
  • --vivisimo

阅读排行榜

评论排行榜

动态生成与编译(一)----入门

 

以前走马观灯似的看.NET Framework SDK文档,也没怎么注意它的CodeDOM机制,很多东西一略而过,“喔,有这么回事呀”就算了,至于如何回事其实也是不甚明了。现在工作上的需要要用到这方面的东西,再仔细一看,不得了,.NET Framework的这个CodeDOM太厉害了。

.NET Framework 中包含一个名为代码文档对象模型”(CodeDOM) 的机制,该机制使编写源代码的程序的开发人员可以在运行时,根据表示所呈现代码的单一模型,用多种编程语言生成源代码。

为表示源代码,CodeDOM 元素相互链接以形成一个数据结构(称为 CodeDOM 图),它以某种源代码的结构为模型。

System.CodeDom 命名空间定义可以表示源代码的逻辑结构(与具体的编程语言无关)的类型。System.CodeDom.Compiler 命名空间定义从 CodeDOM 图生成源代码的类型,和在受支持的语言中管理源代码编译的类型。编译器供应商或开发人员可以扩展受支持语言的集合。

----.NET Framework SDK文档>>使用.NET Framework SDK编程>>动态生成和编译以多种语言表示的源代码

看文字没什么好看的,看下面的代码明了(这是SDK文档上的一些例子拼拼凑凑出来的)

 

using System;

using System.CodeDom;

using System.CodeDom.Compiler;

using Microsoft.CSharp;

using System.IO;

using System.Collections;

 

namespace DemoCodeDOM

{

     class Class1

     {

          [STAThread]

          static void Main(string[] args)

           {

                GenerateCode();

                System.Console.WriteLine("Generate Code OK");

                CompilerResults crt = CompileCode("GenCodeHello.cs");

 

                //下面是编译的结果

                // If errors occurred during compilation, output the compiler output and errors.

                if( crt.Errors.Count > 0 ) {

                     for( int i=0; i<crt.Output.Count; i++ )               

                          Console.WriteLine( crt.Output[i] );

                     for( int i=0; i<crt.Errors.Count; i++ )               

                          Console.WriteLine( i.ToString() + ": " + crt.Errors[i].ToString() );

       

                }

                else {

                     // Display information about the compiler's exit code and the generated assembly.

                     Console.WriteLine( "Compiler returned with result code: " + crt.NativeCompilerReturnValue.ToString() );

                     Console.WriteLine( "Generated assembly name: " + crt.CompiledAssembly.FullName );

                     if( crt.PathToAssembly == null )

                          Console.WriteLine( "The assembly has been generated in memory." );

                     else

                          Console.WriteLine( "Path to assembly: " + crt.PathToAssembly );

        

                     // Display temporary files information.

                     if( !crt.TempFiles.KeepFiles )               

                          Console.WriteLine( "Temporary build files were deleted." );

                     else {

                          Console.WriteLine( "Temporary build files were not deleted." );

                           // Display a list of the temporary build files

                          IEnumerator enu = crt.TempFiles.GetEnumerator();                                       

                          for( int i=0; enu.MoveNext(); i++ )                                         

                                Console.WriteLine( "TempFile " + i.ToString() + ": " + (string)enu.Current );                 

                     }

                }

 

                System.Console.Read();

           }

 

           //生成CodeDOM图,这一步是最复杂的部分,后面生成代码与编译都是以这里的东西为蓝本

          private static CodeCompileUnit ComplieUnit() {

                //生成一个可编译的单元,这是最根部的东西

                CodeCompileUnit compunit = new CodeCompileUnit();

                CodeNamespace sample = new CodeNamespace("Sample");//定义一个名为Sample的命名空间

               

 

                CodeTypeDeclaration MyClass = new CodeTypeDeclaration("DemoClass");//定义一个名为DemoClass的类

               

                CodeEntryPointMethod Start = new CodeEntryPointMethod();//定义程序入口点,就是Main()

                //下面两句产生调用方法的语句

                CodeMethodInvokeExpression cs = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"),

                     "WriteLine",new CodePrimitiveExpression("Hello World!"));//这句会产生如下的C#代码 System.Console.WriteLine("Hello World!");

                CodeMethodInvokeExpression wt = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"),

                     "Read");//这句是 System.Console.Read();

 

                //下面一系列语句把上述定义好的元素联接起来

                compunit.Namespaces.Add(sample);

                sample.Imports.Add(new CodeNamespaceImport("System"));//导入System命名空间

                sample.Types.Add(MyClass);

                MyClass.Members.Add(Start);

                Start.Statements.Add(cs);

                Start.Statements.Add(wt);

          

                return compunit;

           }

 

           //根据CodeDOM产生程序代码,代码文件就是GenCodeHello.cs

          public static void GenerateCode() {

                CSharpCodeProvider cprovider = new CSharpCodeProvider();//当然换个Microsoft.VisualBasic.VBCodeProvider就产生VB.NET的代码

                ICodeGenerator gen = cprovider.CreateGenerator();

                StreamWriter sw = new StreamWriter("GenCodeHello.cs",false);

                gen.GenerateCodeFromCompileUnit(ComplieUnit(),sw,new CodeGeneratorOptions());

 

                sw.Close();

           }

 

           //编译源代码

          public static CompilerResults CompileCode(string filepath) {

                CSharpCodeProvider cprovider = new CSharpCodeProvider();

                ICodeCompiler compiler = cprovider.CreateCompiler();

 

                //编译参数

                CompilerParameters cp = new CompilerParameters(new string[] {"System.dll"},filepath.Substring(0,filepath.LastIndexOf(".") + 1) + "exe",false);

                cp.GenerateExecutable = true;//生成EXE,不是DLL

 

                CompilerResults cr = compiler.CompileAssemblyFromFile(cp,filepath);

                return cr;

           }

     }

}

 

上述的产生的程序代码实际上很简单的一个东西,就是一个控制台输出“Hello Word!”,为了不让它一闪而过,什么也看不清,再加一句read()让它等在那里而已。

上面代码的主要奥秘就是在CodeCompileUnit()这个方法里,生成CodeDOM图的基本代码其实是没什么很难的东西,主要是烦而已,就是定义一些元素,然后把它们连起来。上面为了能清晰的看出生成代码的程序结构把那些Add语句从上到下的全写在一起了。

即使要生成的代码比上面这个例子复杂多了,基本的东西还是没变的,就是定义的东西多一点而已,.NET Framework提供生成的元素是非常之多,好象大多数的语言功能都有,比如上面的定义类,还可以定义结构、枚举;类里面的方法、属性、字段及构造函数;定义Attribute;事件及委托;赋值、条件(if)、循环(for)语句;变量声明;异常处理语句;甚至还可以加注释。除了那种分支选择(switchselect)while循环及breakcontinue没发现外(goto倒是看到了)其他东西应有尽有,至少还没发现什么大的功能无法实现的。真的太强大了。

今天先到这里,主要是入门。以后再好好研究,后面不知从那里开始写有点迷糊,得去找个有几代表性的程序,然后一点点分析要生成如此这般的代码应该是写成怎样的CodeDOM

posted on 2004-10-20 13:43 lichdr 阅读(4755) 评论(7)  编辑 收藏 所属分类: CodeDOM

评论

#1楼  2004-11-25 18:38 skywood [未注册用户]

其实在你CompileUnit之后根本不用再生成源代码,直接用CodeDom编译就可以了   回复  引用    

#2楼  2004-11-25 18:42 skywood [未注册用户]

另外将需要的namespace引用了之后,就可以直接使用CodeSnippetExpression来写连续的代码块了   回复  引用    

#3楼 [楼主] 2004-11-27 14:55 lichdr      

一.CodeCompile是可以直接编译codedom的.这里既然讲就讲全面一点喽.(不过在内部还是生成文件的,最后调用的是CompileAssemblyFromFileBatch这个方法)

在CodeDOM里有一些Snippet的类是可以直接生成代码块的,但那样写的话一点优势都没有.首先把代码写死了,无法产生灵活的程序,再就是无法提供多语言的代码.
(Snippet主要用于产生无法一般CodeDOM的类无法产生的情况)

二.还不如通过TextWriter直接产生代码到文件里来的省事(ICodeGenerator实际也是通过Writer,一句一句的往里写字符串的).   回复  引用  查看    

#4楼  2005-09-26 00:08 lee [未注册用户]

int num = Console.Read();
在其中输入的NUM值并不是NUM的值
请问为什么在C#中输入数字会错误,应该用什么语句解决的
  回复  引用    

#5楼 [楼主] 2005-10-28 17:33 lichdr      

to lee
数据类型的问题吧   回复  引用  查看    

#6楼  2006-08-06 12:58 main      

很好的文章~!谢了   回复  引用  查看    

#7楼  2007-05-03 09:45 Anders.Zhao      

好文章,受教了.   回复  引用  查看    


标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2004-11-03 14:07 编辑过