使用CODEDOM动态实现代码的生成,编译

类别:.NET开发 点击:0 评论:0 推荐:

前一阶段一直在做一个基于VS.NET2k3的一个插件,大致功能是实现业务代码的自动生成。程序在前几天终于突破性的进展,所有的功能都能实现了。包括自动添加工程,引用,编译等。等再过些天,把代码进行优化一些(同时去除一些BUG,一直不明白,当产生几万行代码后,我的开发环境会全面崩溃了)再发布出来吧。昨天突然想到,现在产生的代码过于生,不能根据用户的选择来生成对应的语言的代码。如果死写的话,也太没意思了。想到以前曾看过MSDN里介绍过CODEDOM这玩意能生成各门语言的代码,能动态调用编译,于是快速将CODEDOM再看一次,果然能生成C#,VB,JSCRIPT的代码。不过刚开始研究,只写了一个小小的程序。不过也觉得很有意思的。这样的话,我只要将我的TOOLKIT重写一下就可以让不同的程序员根据自己的喜好生成对应的代码了(功能都是一样的。)

using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Microsoft.CSharp;
using Microsoft.VisualBasic;
using Microsoft.JScript;
//这个示例演示如何使用System.CodeDom来建立一个HELLO World程序,将会根据用户的选择动态代码生成及编译的C#,VB,JScript版本的程序集

namespace CodeDOMTest
{   
 
 public class CodeDomExampleForm : System.Windows.Forms.Form
 {
  private System.Windows.Forms.Button run_button = new System.Windows.Forms.Button();
  private System.Windows.Forms.Button compile_button = new System.Windows.Forms.Button();
  private System.Windows.Forms.Button generate_button = new System.Windows.Forms.Button();
  private System.Windows.Forms.TextBox textBox1 = new System.Windows.Forms.TextBox();
  private System.Windows.Forms.ComboBox comboBox1 = new System.Windows.Forms.ComboBox();
  private System.Windows.Forms.Label label1 = new System.Windows.Forms.Label();
       
  private void generate_button_Click(object sender, System.EventArgs e)
  {
   CodeDomProvider provider = GetCurrentProvider();
   CodeDomExample.GenerateCode(provider, CodeDomExample.BuildHelloWorldGraph());
           
   StreamReader sr = new StreamReader("MyHello.cs");
   textBox1.Text = sr.ReadToEnd();
   sr.Close();
  }

  private void compile_button_Click(object sender, System.EventArgs e)
  {
   CodeDomProvider provider = GetCurrentProvider();
   CompilerResults cr = CodeDomExample.CompileCode(provider, "MyHello.cs");

   if(cr.Errors.Count > 0)
   {
    textBox1.Text = "编译文件出错: "+cr.PathToAssembly+": \r\n";
    foreach(CompilerError ce in cr.Errors)               
     textBox1.AppendText(ce.ToString()+"\r\n");                               
    run_button.Enabled = false;
   }
   else
   {
    textBox1.Text = cr.PathToAssembly+" 编译成功";
    run_button.Enabled = true;
   }
  }

  private void run_button_Click(object sender, System.EventArgs e)
  {
   Process.Start("MyHello.exe");           
  }
       
  /// <summary>
  /// 根据用户的选择返回不同语言的代码生成器
  /// </summary>
  /// <returns></returns>
  private CodeDomProvider GetCurrentProvider()
  {
   CodeDomProvider provider;
   switch((string)this.comboBox1.SelectedItem)
   {
    case "CSharp":
     provider = new CSharpCodeProvider();
     break;
    case "Visual Basic":
     provider = new VBCodeProvider();
     break;
    case "JScript":
     provider = new JScriptCodeProvider();
     break;
    default:
     provider = new CSharpCodeProvider();
     break;
   }
   return provider;
  }
  
  public CodeDomExampleForm()
  {
   this.SuspendLayout();           
   this.label1.Location = new System.Drawing.Point(395, 20);
   this.label1.Size = new Size(180, 22);
   this.label1.Text = "Select a programming language:";           
   this.comboBox1.Location = new System.Drawing.Point(560, 16);
   this.comboBox1.Size = new Size(190, 23);
   this.comboBox1.Name = "comboBox1";
   this.comboBox1.Items.AddRange( new string[] { "CSharp", "Visual Basic", "JScript" } );
   this.comboBox1.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Top;
   this.comboBox1.SelectedIndex = 0;        
   this.generate_button.Location = new System.Drawing.Point(8, 16);
   this.generate_button.Name = "generate_button";
   this.generate_button.Size = new System.Drawing.Size(120, 23);           
   this.generate_button.Text = "Generate Code";
   this.generate_button.Click += new System.EventHandler(this.generate_button_Click);           
        
   this.compile_button.Location = new System.Drawing.Point(136, 16);
   this.compile_button.Name = "compile_button";
   this.compile_button.Size = new System.Drawing.Size(120, 23);           
   this.compile_button.Text = "Compile";
   this.compile_button.Click += new System.EventHandler(this.compile_button_Click);           
 
   this.run_button.Enabled = false;
   this.run_button.Location = new System.Drawing.Point(264, 16);
   this.run_button.Name = "run_button";
   this.run_button.Size = new System.Drawing.Size(120, 23);           
   this.run_button.Text = "Run";
   this.run_button.Click += new System.EventHandler(this.run_button_Click);           
          
   this.textBox1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
    | System.Windows.Forms.AnchorStyles.Left)
    | System.Windows.Forms.AnchorStyles.Right);
   this.textBox1.Location = new System.Drawing.Point(8, 48);
   this.textBox1.Multiline = true;
   this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
   this.textBox1.Name = "textBox1";
   this.textBox1.Size = new System.Drawing.Size(744, 280);           
   this.textBox1.Text = "";           
   // CodeDomExampleForm           
   this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
   this.ClientSize = new System.Drawing.Size(768, 340);
   this.MinimumSize = new System.Drawing.Size(750, 340);
   this.Controls.AddRange(new System.Windows.Forms.Control[] {    this.textBox1, this.run_button, this.compile_button, this.generate_button, this.comboBox1, this.label1 });
   this.Name = "CodeDomExampleForm";
   this.Text = "CodeDom Hello World Example";
   this.ResumeLayout(false);
  }

  protected override void Dispose( bool disposing )
  {
   base.Dispose( disposing );
  }

  private void InitializeComponent()
  {
   this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
   this.ClientSize = new System.Drawing.Size(448, 269);
   this.Name = "CodeDomExampleForm";

  }

  [STAThread]
  static void Main()
  {
   Application.Run(new CodeDomExampleForm());
  }
 }

 public class CodeDomExample
 {

  public static CodeCompileUnit BuildHelloWorldGraph()
  {           
   //建立一个代码容器
   //CodeCompileUnit 包含以下几个集合:可以存储包含 CodeDOM 源代码图形的 CodeNamespace 对象的集合、
   //项目引用的程序集的集合,以及项目程序集的属性集合。
   CodeCompileUnit CompileUnit = new CodeCompileUnit();

   // 声明一个名称空间
   CodeNamespace MySample = new CodeNamespace("MySample");
   // 将名称空间加入到代码容器
   CompileUnit.Namespaces.Add( MySample );
   
   // 导入一个名称空间
   MySample.Imports.Add( new CodeNamespaceImport("System") );           

   // 声明一个类型
   CodeTypeDeclaration Hello = new CodeTypeDeclaration("Hello");
   // 将类型加入到容器的类型集合中
   MySample.Types.Add(Hello);
           
   // 构造函数(并非必须)
   CodeConstructor con = new CodeConstructor();
   con.Attributes = MemberAttributes.Public | MemberAttributes.Final;
   Hello.Members.Add(con);
   // 表示可执行文件的入口点方法,也就是一个程序的入口
   CodeEntryPointMethod Start = new CodeEntryPointMethod();
   // 建立一个代码调用的表达式
   CodeMethodInvokeExpression cs1 = new CodeMethodInvokeExpression(
    // 调用方法. System.Console.WriteLine
    new CodeTypeReferenceExpression("System.Console"), "WriteLine",
    // 给方法传一个基元数据类型的值
    new CodePrimitiveExpression("Hello World!") );
   // 将方法加入到方法中
   Start.Statements.Add(new CodeExpressionStatement(cs1));
   CodeMethodInvokeExpression cs2 = new CodeMethodInvokeExpression();
   CodeMethodReferenceExpression cmr=new CodeMethodReferenceExpression();
   cmr.MethodName="SayHell";
   cs2.Method=cmr;
   
   Start.Statements.Add(new CodeExpressionStatement(cs2));

   // 将方法加入到类型中
   Hello.Members.Add( Start );

   // 成员函数SayHello,有参数,无返回值

//   public bool SayHello(string input)
//   {
//    Console.WriteLine(input);
//    return false;
//   }
   CodeMemberMethod cm = new CodeMemberMethod();
   cm.Name = "SayHello";
   
   cm.ReturnType=new CodeTypeReference(typeof(bool));
   cm.Attributes = MemberAttributes.Public | MemberAttributes.Final|MemberAttributes.Static;
   cm.Parameters.Add(
    new CodeParameterDeclarationExpression(
    typeof(string),"input"));
   cm.Statements.Add(
    new CodeMethodInvokeExpression(
    new CodeSnippetExpression("Console"),"WriteLine",
    new CodeArgumentReferenceExpression("input")));
   cm.Statements.Add(new CodeMethodReturnStatement( new CodePrimitiveExpression(false)));
   Hello.Members.Add(cm);

   return CompileUnit;
  }

  public static void GenerateCode(CodeDomProvider provider, CodeCompileUnit compileunit)
  {
   //获得生成代码的接口
   ICodeGenerator gen = provider.CreateGenerator();
   // 输出到文件
   IndentedTextWriter tw = new IndentedTextWriter(new StreamWriter("MyHello.cs", false), "    ");
   // 使用代码生成接口产生源代码.
   gen.GenerateCodeFromCompileUnit(compileunit, tw, new CodeGeneratorOptions());
   
   tw.Close();           
  }

  public static CompilerResults CompileCode(CodeDomProvider provider, string filepath)
  {
   // 获得编译器.      
   ICodeCompiler compiler = provider.CreateCompiler();
   //配置编译参数。将SYSTEM。DLL引用进来,同时明确生成的代码为EXE
 
   CompilerParameters cp = new CompilerParameters(new string[] {"System.dll"}, filepath.Substring(0, filepath.LastIndexOf(".")+1)+"exe", false);
 
   cp.GenerateExecutable = true;           
   // 调用编译器
   CompilerResults cr = compiler.CompileAssemblyFromFile(cp, filepath);
   
   return cr;
  }
 }

}
上面的代码还有一点没实现。

本文地址:http://com.8s8s.com/it/it42549.htm