利用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);
}
}
}
本文转自博客园伍华聪的博客,原文链接: 利用Refly和CodeDom实现代码的动态生成和动态编译,如需转载请自行联系原博主。


目录
相关文章
|
存储 Linux 调度
io复用之epoll核心源码剖析
epoll底层实现中有两个关键的数据结构,一个是eventpoll另一个是epitem,其中eventpoll中有两个成员变量分别是rbr和rdlist,前者指向一颗红黑树的根,后者指向双向链表的头。而epitem则是红黑树节点和双向链表节点的综合体,也就是说epitem即可作为树的节点,又可以作为链表的节点,并且epitem中包含着用户注册的事件。当用户调用epoll_create()时,会创建eventpoll对象(包含一个红黑树和一个双链表);
284 0
io复用之epoll核心源码剖析
|
存储 数据可视化 数据挖掘
图书馆图书可视化分析+大屏
在数字化时代背景下,图书馆已经成为知识获取和共享的重要场所。然而,随着馆藏书籍数量的增加,如何高效管理和利用这些资源成为了图书馆管理者和用户面临的挑战。数据分析和可视化技术的引入为解决这一问题提供了新的途径。本文致力于通过数据分析技术和可视化手段,对图书馆书籍数据进行综合挖掘,希望通过图书分类、书籍价格及读者偏好等多维度信息,进而优化图书馆管理策略、指导书籍采购决策并提升读者服务质量。本文在数字化和信息化快速发展的背景下,图书馆如何利用数据分析与可视化方法来挖掘和优化书籍借阅数据。主要内容包括。
1238 2
|
人工智能 关系型数据库 MySQL
基于阿里云的PolarDB MySQL版实现AI增强数据管理
本文将介绍如何利用阿里云的PolarDB MySQL版结合AI技术,实现数据管理的自动化和智能化。
1005 0
|
机器学习/深度学习 人工智能 搜索推荐
AI技术在医疗领域的应用:未来已来####
本文深入探讨了人工智能(AI)技术在医疗领域的革命性应用,重点分析了其在疾病诊断、个性化治疗、药物研发及患者管理等方面的突破。通过具体实例展示了AI如何提升医疗服务效率与质量,同时讨论了伴随技术进步而来的伦理、隐私与数据安全等挑战,并对未来AI医疗的发展趋势进行了展望。 ####
260 27
|
12月前
|
机器学习/深度学习 人工智能 算法
VE-Bench:北京大学开源首个针对视频编辑质量的评估指标,从多角度考虑审美并准确地评估视频编辑效果
北京大学开源了首个针对视频编辑质量评估的新指标 VE-Bench,旨在通过人类感知一致的度量标准,更准确地评估视频编辑效果。
683 14
VE-Bench:北京大学开源首个针对视频编辑质量的评估指标,从多角度考虑审美并准确地评估视频编辑效果
|
存储 人工智能 算法
卷起来!让智能体评估智能体,Meta发布Agent-as-a-Judge
Meta(原Facebook)提出了一种名为Agent-as-a-Judge的框架,用于评估智能体的性能。该框架包含八个模块,通过构建项目结构图、定位相关文件、读取多格式数据、搜索和检索信息、询问要求满足情况、存储历史判断、以及规划下一步行动,有效提升了评估的准确性和稳定性。实验结果显示,Agent-as-a-Judge在处理复杂任务依赖关系方面优于大型语言模型,但在资源消耗和潜在偏见方面仍面临挑战。
517 1
|
JSON NoSQL Redis
Redis 作为向量数据库快速入门指南
Redis 作为向量数据库快速入门指南
1218 1
|
算法
路径规划算法 - 求解最短路径 - Dijkstra(迪杰斯特拉)算法
路径规划算法 - 求解最短路径 - Dijkstra(迪杰斯特拉)算法
840 0
|
消息中间件 Linux 开发工具
Linux系统安装RabbitMQ详细教程
Linux系统安装RabbitMQ详细教程
460 0