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