现在的位置: 首页 > 综合 > 正文

动态代码生成

2018年02月07日 ⁄ 综合 ⁄ 共 11083字 ⁄ 字号 评论关闭

【文章标题】: 动态代码生成02
【文章作者】: 有酒醉
【作者邮箱】: wuqr32@sina.com
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  2、采用DOM生成动态代码
  步骤:
  a、创建一个CodeCom的根,CodeCompileUnit
  b、添加自定义命名空间,CodeCompileUnit.Namespaces.Add(CodeNamespace cn)
  c、添加所需的命名空间,CodeNamespace.Imports.Add(CodeNamespaceImport cn)
  d、在自定义命名空间中添加类,CodeNamespace.Types.Add(CodeTypeDeclaration ctd);
  e、在自定义类中添加方法和属性,CodeTypeDeclaration.Members.Add(CodeTypeMember ctm)
  f、为方法添加语句,CodeMemberMethod.Statements.Add(CodeStatement cs)
  g、为属性添加类型和初始值,CodeMemberField.Type,CodeMemberField.InitExpression
  h、将DOM转换为源代码,CSharpCodeProvider.CreateGenerator().GenerateCodeFromCompileUnit()
  i、或将DOM转换为程序集,CSharpCodeProvider.CreateCompiler().CompileAssemblyFromFile()
 
  2.1、源代码 -- 创建CodeDom模型的程序
  首先,我们打算动态生成的程序结构大致如下:
  // CodeDomDemo.cs
  // Author by Yzl
 
  using System;
 
  namespace com.diao.yzl
  {
   public class CodeDomDemo
   {
    public static void Main(string[] args)
    {   
     try
     {
      if (args.Length != 2)
      {     
       throw new Exception("Usage:CodeDomDemo  ");
      }
      int iCount = Int32.Parse(args[1]);
      
      for (int i = 0;i < iCount; i ++)
       Console.WriteLine(args[0]);
     }
     catch(Exception ex)
     {
      Console.WriteLine(ex.Message);
     }
    }
   }
  }
 
  先编译运行看效果:
  D:/>csc CodeDomDemo.cs
  Microsoft (R) Visual C# .NET 编译器版本 7.10.6001.4
  用于 Microsoft (R) .NET Framework 版本 1.1.4322
  版权所有 (C) Microsoft Corporation 2001-2002。保留所有权利。
 
 
  D:/>CodeDomDemo
  Usage:CodeDomDemo 
 
  D:/>CodeDomDemo "Hello Yzl" 5
  Hello Yzl
  Hello Yzl
  Hello Yzl
  Hello Yzl
  Hello Yzl
 
 
  其次,我们用CodeDom技术动态生成并运行它
  // T.cs
  // Author by Yzl
 
  using System;
  using System.IO;
  using System.Reflection;
  using System.CodeDom.Compiler;
  using System.CodeDom;
  using Microsoft.CSharp;
 
  public class T
  {
   public static void Main(string[] args)
   {
    
    // 创建一个CodeCom的根
    CodeCompileUnit codeDomDemoUnit = new CodeCompileUnit();
    
    // 添加自定义命名空间
    CodeNamespace codeDomDemoNamespace = new CodeNamespace("com.diao.yzl");
    codeDomDemoUnit.Namespaces.Add(codeDomDemoNamespace);
    
    // 添加所需的命名空间
    CodeNamespaceImport systemNamespaceImport = new CodeNamespaceImport("System");
    codeDomDemoNamespace.Imports.Add(systemNamespaceImport);
    
    // 在自定义命名空间中添加类
    CodeTypeDeclaration CodeDomDemoTypeDec = new CodeTypeDeclaration("CodeDomDemo");
    CodeDomDemoTypeDec.TypeAttributes = TypeAttributes.Public|TypeAttributes.Class;
    codeDomDemoNamespace.Types.Add(CodeDomDemoTypeDec);
    
    // 在自定义类中添加Main方法
    //CodeEntryPointMethod mainMethod = new CodeEntryPointMethod();
    //mainMethod.Name = "Main";    
    //CodeDomDemoTypeDec.Members.Add(mainMethod);
    CodeMemberMethod mainMethod = new CodeMemberMethod();
    mainMethod.Name = "Main";
    mainMethod.Attributes = MemberAttributes.Public|MemberAttributes.Static;   
    CodeDomDemoTypeDec.Members.Add(mainMethod);
    // 添加参数string[] args
    CodeTypeReference argsTypeRef = new CodeTypeReference(new CodeTypeReference(typeof(string)),1);
    CodeParameterDeclarationExpression argsExp = new CodeParameterDeclarationExpression(argsTypeRef,"args");
    mainMethod.Parameters.Add(argsExp);
    
    // 为方法添加try语句
    CodeTryCatchFinallyStatement tryStatement = new CodeTryCatchFinallyStatement();
    mainMethod.Statements.Add(tryStatement);
    // 添加if语句到try中
    CodeConditionStatement ifStatement = new CodeConditionStatement();
    tryStatement.TryStatements.Add(ifStatement);
    // 获取 args.Length
    CodeVariableReferenceExpression argsRef5 = new CodeVariableReferenceExpression("args");
    CodePropertyReferenceExpression argsLengthExp = new CodePropertyReferenceExpression(argsExp,"Length");
    // args.Length != 2
    ifStatement.Condition = new CodeBinaryOperatorExpression(argsLengthExp,CodeBinaryOperatorType.IdentityInequality,
        new CodePrimitiveExpression(2));
    // 条件为真时,抛出异常语句
    CodeThrowExceptionStatement throwException = new CodeThrowExceptionStatement(
     new CodeObjectCreateExpression(new CodeTypeReference(typeof(System.Exception)),
        new CodeExpression[]{new CodePrimitiveExpression("Usage:CodeDomDemo  ")}));
    ifStatement.TrueStatements.Add(throwException);
    
    // 在try中添加 int iCount = Int32.Parse(args[1]);
    CodeVariableDeclarationStatement iCountVarStatement = new CodeVariableDeclarationStatement();
    iCountVarStatement.Name = "iCount";
    // args[1]
    CodeArrayIndexerExpression arg1Exp = new CodeArrayIndexerExpression(argsExp, new CodePrimitiveExpression(1));
    iCountVarStatement.InitExpression = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(typeof(Int32)),"Parse",new CodeExpression[]{arg1Exp});
    tryStatement.TryStatements.Add(iCountVarStatement);
     
    // 声明 int i = 0
    CodeVariableDeclarationStatement iDeclare = new CodeVariableDeclarationStatement();
    iDeclare.Name = "i";
    iDeclare.InitExpression = new CodePrimitiveExpression(0);
    
    // i = i + 1
    CodeVariableReferenceExpression iVar = new CodeVariableReferenceExpression("i");
    CodeAssignStatement incI = new CodeAssignStatement();
    incI.Left = iVar;
    incI.Right = new CodeBinaryOperatorExpression(iVar,CodeBinaryOperatorType.Add,new CodePrimitiveExpression(1));
    
    // for (int i = 0;i < iCount; i ++)
    CodeIterationStatement forStatement = new CodeIterationStatement();
    forStatement.InitStatement = iDeclare;
    CodeVariableReferenceExpression iCountVarRef = new CodeVariableReferenceExpression(iCountVarStatement.Name);
    forStatement.TestExpression = new CodeBinaryOperatorExpression(iVar,CodeBinaryOperatorType.LessThan,iCountVarRef);
    
    // 传递给Console.WriteLine()的参数
    CodeExpression[] writeLineArgs = new CodeExpression[1];
    CodeArrayIndexerExpression arg0Exp = new CodeArrayIndexerExpression(argsExp, new CodePrimitiveExpression(0));
    writeLineArgs[0] = arg0Exp;
    
    // 产生Console.WriteLine(args[0]);语句
    CodeTypeReferenceExpression consoleRef = new CodeTypeReferenceExpression(typeof(Console));
    CodeMethodReferenceExpression writeLineRef = new CodeMethodReferenceExpression(consoleRef,"WriteLine");
    CodeMethodInvokeExpression writeLineExp = new CodeMethodInvokeExpression(writeLineRef,writeLineArgs);
    forStatement.Statements.Add(writeLineExp);
    // 添加for到try中
    tryStatement.TryStatements.Add(forStatement);
    
    // 处理Catch语句
    CodeCatchClause catchCla = new CodeCatchClause("ex",new CodeTypeReference(typeof(Exception)));
    // ex.Message
    CodeVariableReferenceExpression exRef = new CodeVariableReferenceExpression(catchCla.LocalName);
    CodePropertyReferenceExpression msgRef = new CodePropertyReferenceExpression(exRef,"Message");
    writeLineExp = new CodeMethodInvokeExpression(writeLineRef,new CodeExpression[]{msgRef} );
    catchCla.Statements.Add(writeLineExp);
    // 添加catch到try中
    tryStatement.CatchClauses.Add(catchCla);
    
    // 添加Return 语句到Main函数
    CodeMethodReturnStatement retMethod = new CodeMethodReturnStatement();
    mainMethod.Statements.Add(retMethod);
    
 
    // 生成cs代码
    CodeGeneratorOptions cgo = new CodeGeneratorOptions();
    cgo.BracingStyle = "C";
    cgo.IndentString = "/t";
    CSharpCodeProvider cscp = new CSharpCodeProvider();
    ICodeGenerator igen = cscp.CreateGenerator();
    StreamWriter sw = new StreamWriter("CodeDomDemo2.cs");
    igen.GenerateCodeFromCompileUnit(codeDomDemoUnit,sw,cgo);
    sw.Close();
   }
  }
 
  编译成功,但是运行出错,同时请注意注释掉的这句代码:
  //CodeEntryPointMethod mainMethod = new CodeEntryPointMethod();
  //mainMethod.Name = "Main";    
  //CodeDomDemoTypeDec.Members.Add(mainMethod);
 
  如果用CodeEntryPointMethod的话,生成的Main方法不保存形参,这真是的奇怪的现象.我做了个测试如下:
  using System;
  using System.IO;
  using System.Reflection;
  using System.CodeDom.Compiler;
  using System.CodeDom;
  using Microsoft.CSharp;
 
  public class T2
  {
   public static void Main(string[] args)
   {
    
    // 创建一个CodeCom的根
    CodeCompileUnit codeDomDemoUnit = new CodeCompileUnit();
    
    // 添加自定义命名空间
    CodeNamespace codeDomDemoNamespace = new CodeNamespace("com.diao.yzl");
    codeDomDemoUnit.Namespaces.Add(codeDomDemoNamespace);
    
    // 添加所需的命名空间
    CodeNamespaceImport systemNamespaceImport = new CodeNamespaceImport("System");
    codeDomDemoNamespace.Imports.Add(systemNamespaceImport);
    
    // 在自定义命名空间中添加类
    CodeTypeDeclaration CodeDomDemoTypeDec = new CodeTypeDeclaration("CodeDomDemo");
    CodeDomDemoTypeDec.TypeAttributes = TypeAttributes.Public|TypeAttributes.Class;
    codeDomDemoNamespace.Types.Add(CodeDomDemoTypeDec);
    
    // 在自定义类中添加Main方法
    CodeEntryPointMethod mainMethod = new CodeEntryPointMethod();
    mainMethod.Name = "Main";    
    CodeDomDemoTypeDec.Members.Add(mainMethod);
    // 添加参数string[] args 
    CodeTypeReference argsTypeRef = new CodeTypeReference(new CodeTypeReference(typeof(string)),1);
    CodeParameterDeclarationExpression argsExp = new CodeParameterDeclarationExpression(argsTypeRef,"args");
    mainMethod.Parameters.Add(argsExp);
    
    CodeMemberMethod method1 = new CodeMemberMethod();           
    method1.Name = "ReturnString";
    method1.ReturnType = new CodeTypeReference("System.String");
    method1.Parameters.Add( new CodeParameterDeclarationExpression("System.String", "text") );
    method1.Statements.Add( new CodeMethodReturnStatement( new CodeArgumentReferenceExpression("text") ) );
    CodeDomDemoTypeDec.Members.Add(method1);
 
    
    // 为方法添加try语句
    CodeTryCatchFinallyStatement tryStatement = new CodeTryCatchFinallyStatement();
    mainMethod.Statements.Add(tryStatement);
    
    // 处理Catch语句
    CodeCatchClause catchCla = new CodeCatchClause("ex",new CodeTypeReference(typeof(Exception)));
    // ex.Message
    CodeVariableReferenceExpression exRef = new CodeVariableReferenceExpression(catchCla.LocalName);
    CodePropertyReferenceExpression msgRef = new CodePropertyReferenceExpression(exRef,"Message");
    CodeTypeReferenceExpression consoleRef = new CodeTypeReferenceExpression(typeof(Console));
    CodeMethodReferenceExpression writeLineRef = new CodeMethodReferenceExpression(consoleRef,"WriteLine");
    CodeMethodInvokeExpression writeLineExp = new CodeMethodInvokeExpression(writeLineRef,new CodeExpression[]{msgRef} );
    catchCla.Statements.Add(writeLineExp);
    // 添加catch到try中
    tryStatement.CatchClauses.Add(catchCla);
    
    // 添加Return 语句到Main函数
    CodeMethodReturnStatement retMethod = new CodeMethodReturnStatement();
    mainMethod.Statements.Add(retMethod);
    
    // 生成cs代码
    CodeGeneratorOptions cgo = new CodeGeneratorOptions();
    cgo.BracingStyle = "C";
    cgo.IndentString = "/t";
    CSharpCodeProvider cscp = new CSharpCodeProvider();
    ICodeGenerator igen = cscp.CreateGenerator();
    StreamWriter sw = new StreamWriter("CodeDomDemo2.cs");
    igen.GenerateCodeFromCompileUnit(codeDomDemoUnit,sw,cgo);
    sw.Close();
   }
  }
  编译运行:
  D:/>csc T2.cs
  Microsoft (R) Visual C# .NET 编译器版本 7.10.6001.4
  用于 Microsoft (R) .NET Framework 版本 1.1.4322
  版权所有 (C) Microsoft Corporation 2001-2002。保留所有权利。
 
 
  D:/>T2.exe
 
  得出结果出乎意料:
  //------------------------------------------------------------------------------
  //
  //     This code was generated by a tool.
  //     Runtime Version: 1.1.4322.2032
  //
  //     Changes to this file may cause incorrect behavior and will be lost if
  //     the code is regenerated.
  //
  //------------------------------------------------------------------------------
 
  namespace com.diao.yzl
  {
   using System;
   
   
   public class CodeDomDemo
   {
    // 注意!!这边并不包含形参!!
    public static void Main()
    {
     try
     {
     }
     catch (System.Exception ex)
     {
      System.Console.WriteLine(ex.Message);
     }
     return;
    }
    
    private string ReturnString(string text)
    {
     return text;
    }
   }
  }
 
  另外,更改此小bug之后程序仍然有些小问题,有兴趣的大家可以自己找找.现在太晚了,凌晨4点.已经连续三天没正常睡觉,该好好休息咯.同时,<动态代码生成>
  也该就此告别.明天开始新的历程!
 
  End
 
 
--------------------------------------------------------------------------------
【版权声明】: 本文原创于泉州软件基地, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2007年02月06日 4:16:21

【上篇】
【下篇】

抱歉!评论已关闭.