动态代码生成

    技术2022-05-11  77

    【文章标题】: 动态代码生成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


    最新回复(0)