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