好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

利用Refly和CodeDom实现代码的动态生成和动态编译

利用Refly和CodeDom实现代码的动态生成和动态编译

CodeDom是.NET框架中比较强大也是比较难懂的对象模型,通过它可以实现.NET支持各种语言代码的动态生成及动态编译。我们先来看看CodeDom的定义:.NET Framework 中包含一个名为“代码文档对象模型”(CodeDOM) 的机制,该机制使编写源代码的程序的开发人员可以在运行时,根据表示所呈现代码的单一模型,用多种编程语言生成源代码。

Refly则是国外一个开发者对CodeDom进行封装,目的是使得Codedom的实现更加方便易懂,和CodeDom的使用对比,代码更加简洁优雅,不过要了解整体的东西,也需要对CodeDOM进行详细的了解才能熟练应用。

本人在研究学习Refly当中(详细可以参考 http://www.codeproject.com/Articles/6283/Refly-makes-the-CodeDom-er-life-easier ),对其中简单的应用有一些体会,做了一个使用Refly生成代码的例子进行测试,并使用CodeDOM进行动态编译。例子应该还算简单,用来说明Refly的工作机制应该还是足够的,同时也希望与大家探讨一下进一步的应用。

生成类代码的代码如下所示:

             #region  生成代码

// 创建命名空间
NamespaceDeclaration ns = new NamespaceDeclaration( " Demo " );
ns.Imports.Add( " System.Xml " );
ns.Imports.Add( " System.IO " );
ns.Imports.Add( " System.ComponentModel " );
ns.Imports.Add( " System.Xml.Serialization " );

// 创建类定义
ClassDeclaration user = ns.AddClass( " User " );
// 添加类说明
user.Doc.Summary.AddText( " 测试用户类描述 " );
user.Doc.Remarks.Add( " para " );
user.Doc.Remarks.Into();
user.Doc.Remarks.AddText( " 该类是使用Refly进行生成 " );
user.Doc.Remarks.OutOf();

// 添加字段
FieldDeclaration name = user.AddField( typeof ( string ), " name " );
FieldDeclaration age = user.AddField( typeof ( int ), " age " );

// 添加构造函数(默认)
user.AddConstructor();
ConstructorDeclaration cstr = user.AddConstructor();
// 添加构造函数(参数)
ParameterDeclaration cstr_name = cstr.Signature.Parameters.Add( typeof ( string ), " name " , true );

cstr.Body.AddAssign(Expr.This.Field(name), Expr.Arg(cstr_name));

// 添加属性Name
PropertyDeclaration proName = user.AddProperty(name, true , true , false );
proName.Doc.Summary.AddText( " 用户名称 " );
// 添加属性的Attribute
AttributeDeclaration attr = proName.CustomAttributes.Add( typeof (XmlElementAttribute));
attr.Arguments.Add( " ElementName " , Expr.Prim(proName.Name));

// 添加属性Age
PropertyDeclaration proAge = user.AddProperty(age, true , true , false );
proName.Doc.Summary.AddText( " 用户年龄 " );

// 添加方法
MethodDeclaration add = user.AddMethod( " Add " );
add.Doc.Summary.AddText( " 添加用户内容 " );
ParameterDeclaration pName = add.Signature.Parameters.Add( typeof ( string ), " name " , true );
add.Doc.AddParam(pName);
ParameterDeclaration pAge = add.Signature.Parameters.Add( typeof ( int ), " age " , true );
add.Body.Add(Stm.Assign(Expr.This.Prop( " Name " ), Expr.Arg(pName)));
add.Body.Add(Stm.Assign(Expr.This.Prop( " Age " ), Expr.Arg(pAge)));

// 添加方法2
MethodDeclaration show = user.AddMethod( " Show " );
show.Doc.Summary.AddText( " 输出用户名称 " );
show.Body.Add(Expr.Snippet( " Console " ).Method( " WriteLine " ).Invoke(Expr.This.Prop( " Name " )));

// 输出结果
Refly.CodeDom.CodeGenerator gen = new Refly.CodeDom.CodeGenerator();
gen.Provider = Refly.CodeDom.CodeGenerator.CsProvider;
gen.GenerateCode(Application.StartupPath + " /CS " , ns);

#endregion

复制代码

编译代码好像Refly没有找到,所以用原始的CodeDOM的对象操作进行代码的动态编译,编译代码如下所示:

            #region  动态编译代码

string file = string .Format( " {0}\\CS\\Demo\\User.cs " , Application.StartupPath);
string code = FileUtil.FileToString(file);
string output = string .Format( " {0}\\CS\\Demo\\User.dll " , Application.StartupPath);

CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add( " System.dll " );
parameters.ReferencedAssemblies.Add( " System.Data.dll " );
parameters.ReferencedAssemblies.Add( " System.Xml.dll " );
parameters.GenerateInMemory = false ;
parameters.TreatWarningsAsErrors = false ;
parameters.OutputAssembly = output; // 设定输出文件名称路径

// 判断编译结果
// CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, code);
CompilerResults results = codeProvider.CompileAssemblyFromFile(parameters, file);
if (results.Errors.HasErrors)
{
string errorMessage = "" ;
errorMessage = results.Errors.Count.ToString() + " Errors: " ;
for ( int x = 0 ; x < results.Errors.Count; x++)
{
errorMessage = errorMessage + " \r\nLine: " +
results.Errors[x].Line.ToString() + " - " + results.Errors[x].ErrorText;
}
MessageUtil.ShowError(errorMessage);
}
// string path = results.PathToAssembly;

return results.Errors.Count == 0 ;

#endregion

复制代码

代码编译了,我们使用的编译好的类也就可以了,使用操作代码如下所示,例子我使用反射,把生成的对象加载,并绑定到PropertyGrid控件中。

         private   void  btnTest_Click( object  sender, EventArgs e)
{
GenerateCompile();

string assemblyFile = string .Format( " {0}\\CS\\Demo\\User.dll " , Application.StartupPath);
if (File.Exists(assemblyFile))
{
Assembly assObj = Assembly.LoadFile(assemblyFile);
if (assObj != null )
{
object obj = assObj.CreateInstance( " Demo.User " );
this .propertyGrid1.SelectedObject = obj;
}
}
}

复制代码

最终例子运行的效果如下所示。

其实最终生成的User类代码如下所示。

 //   Generated by Refly  
namespace Demo
{
using System;
using System.Xml;
using System.IO;
using System.ComponentModel;
using System.Xml.Serialization;

/// <summary> 测试用户类描述 </summary>
/// <remarks>
/// <para> 该类是使用Refly进行生成 </para>
/// </remarks>
public class User
{

private int _age;

private string _name;

public User()
{
}

public User( string name)
{
this ._name = name;
}

/// <summary> 用户名称用户年龄 </summary>
[XmlElementAttribute(ElementName= " Name " )]
public virtual string Name
{
get
{
return this ._name;
}
set
{
this ._name = value;
}
}

public virtual int Age
{
get
{
return this ._age;
}
set
{
this ._age = value;
}
}

/// <summary> 添加用户内容 </summary>
/// <param name="name" />
public virtual void Add( string name, int age)
{
this .Name = name;
this .Age = age;
}

/// <summary> 输出用户名称 </summary>
public virtual void Show()
{
Console.WriteLine( this .Name);
}
}
}

复制代码



主要研究技术:代码生成工具、Visio二次开发、送水管理软件等共享软件开发
专注于 Winform开发框架 、WCF开发框架的研究及应用。
  转载请注明出处:
撰写人:伍华聪   http: // www.iqidi.com  
    

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于利用Refly和CodeDom实现代码的动态生成和动态编译的详细内容...

  阅读:45次