.Net拾忆:CodeDom动态源代码生成器和编译器
代码文档模型CodeDom命名空间下主要有两个,很明显第一个代码逻辑分析,第二个负责代码的编译
using System.CodeDom;
using System.CodeDom.Compiler;
一、代码逻辑
1、CodeNamespace创建命名空间
CodeNamespace nspace=new CodeNamespace("Practice.MyNamespace")//创建命名空间
nspace.Imports.Add(new CodeNamespaceImport("System"));//引入程序命名空间:using System;
//nspace.Types 命名空间中所含类的集合,使用add添加
2、CodeTypeDeclaration类定义
CodeTypeDeclaration helloword = new CodeTypeDeclaration("HelloWord");//类型Class声明
helloword.Attributes = MemberAttributes.Public;//public
//helloword.Members.AddRange(new CodeTypeMember[] { method, main });//添加方法到clss
3、CodeMemberMethod/CodeEntryPointMethod方法
CodeMemberMethod method = new CodeMemberMethod();//方法声明;
method.Name = "SayHello";// 方法名
method.Attributes = MemberAttributes.Public | MemberAttributes.Final;//属性
method.ReturnType = new CodeTypeReference(typeof(string));//返回类型
method.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Hello from code!")));
//方法体,只有一句返回语句return "Hello from code!"; CodeEntryPointMethod main = new CodeEntryPointMethod();//主方法Main
main.Statements.Add(new CodeVariableDeclarationStatement("HelloWord", "hw",
new CodeObjectCreateExpression("HelloWord", new CodeExpression[] { })));//变量声明:HelloWord hw = new HelloWord();
4、CodeMethodInvokeExpression表达式
CodeMethodInvokeExpression methodinvoke =
new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("hw"), "SayHello", new CodeExpression[] { });
main.Statements.Add(new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"), "WriteLine", methodinvoke));
main.Statements.Add(new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"), "Read"));
//两个方法调用:System.Console.WriteLine(hw.SayHello());
二、编译
System.CodeDom.Compiler常用类
CodeDomProvider创建编译器
CodeDomProvider provider = CodeDomProvider.CreateProvider("VisualBasic");
CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
CompilerParameters编译器参数
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll"); //添加程序集 system.dll 的引用
cp.GenerateExecutable = false; //不生成可执行文件
cp.GenerateInMemory = true; //在内存中运行
CompilerResults编译结果
//得到编译器实例的返回结果
CompilerResults cr = provider.CompileAssemblyFromSource(cp, code.ToString())
cr.Errors //CompilerError集合、所有编译错误
cr.CompiledAssembly //Assembly、 获取编译结果的程序集
示例一
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Practice.CodeDom.Compiler
{
class Program
{
static void Main(string[] args)
{
Program pro = new Program();
CodeNamespace nspace = pro.CreateCodeDomHelloDemo();
Console.WriteLine(pro.GengerCode(nspace));
string filename = "HelloWorld.exe";
CompilerResults result = pro.Execute(nspace, filename);
if (result.Errors.HasErrors)//是否存在错误;
{
for (int i = ; i < result.Output.Count; i++) Console.WriteLine(result.Output[i]); for (int i = ; i < result.Errors.Count; i++) Console.WriteLine(i.ToString() + ": " + result.Errors[i].ToString());
}
else
{
System.Diagnostics.Process.Start(filename);//这里比较懒,不想动手去自己打开,呵呵;
}
Console.Read();
} public CodeNamespace CreateCodeDomHelloDemo()
{
CodeMemberMethod method = new CodeMemberMethod();//方法声明;
method.Name = "SayHello";// 方法名
method.Attributes = MemberAttributes.Public | MemberAttributes.Final;//属性
method.ReturnType = new CodeTypeReference(typeof(string));//返回类型
method.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression("Hello from code!")));//方法体,只有一句返回语句return "Hello from code!"; CodeEntryPointMethod main = new CodeEntryPointMethod();//主方法Main
main.Statements.Add(new CodeVariableDeclarationStatement("HelloWord", "hw",
new CodeObjectCreateExpression("HelloWord", new CodeExpression[] { })));//变量声明:HelloWord hw = new HelloWord(); CodeMethodInvokeExpression methodinvoke = new CodeMethodInvokeExpression(new CodeVariableReferenceExpression("hw"), "SayHello", new CodeExpression[] { });
main.Statements.Add(new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"), "WriteLine", methodinvoke));
main.Statements.Add(new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("System.Console"), "Read"));//两个方法调用:System.Console.WriteLine(hw.SayHello()); CodeTypeDeclaration helloword = new CodeTypeDeclaration("HelloWord");//类型Class声明
helloword.Attributes = MemberAttributes.Public;
helloword.Members.AddRange(new CodeTypeMember[] { method, main });//添加方法到clss CodeNamespace nspace = new CodeNamespace("HelloDemo1");//命名空间声明
nspace.Imports.Add(new CodeNamespaceImport("System"));//引入程序命名空间:using System;
nspace.Types.Add(helloword);//
return nspace;
} public string GengerCode(CodeNamespace nspace)
{
StringBuilder sb = new StringBuilder();
System.IO.StringWriter sw = new System.IO.StringWriter(sb);
CodeGeneratorOptions geneOptions = new CodeGeneratorOptions();//代码生成选项 geneOptions.BlankLinesBetweenMembers = false; geneOptions.BracingStyle = "C"; geneOptions.ElseOnClosing = true; geneOptions.IndentString = " ";
CodeDomProvider.GetCompilerInfo("c#").CreateProvider().GenerateCodeFromNamespace(nspace, sw, geneOptions);//代码生成
sw.Close();
return sb.ToString(); } public CompilerResults Execute(CodeNamespace nspace, string filename)
{
CodeCompileUnit unit = new CodeCompileUnit();//code编译单元
unit.Namespaces.Add(nspace);
CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
CompilerParameters options = new CompilerParameters();// options.GenerateInMemory = false;//是否在内存中生成;
options.IncludeDebugInformation = true;// 包含调试信息;
options.ReferencedAssemblies.Add("System.dll");
options.OutputAssembly = filename;
if (System.IO.Path.GetExtension(filename).ToLower() == ".exe")
{
options.GenerateExecutable = true;//true为可执行exe,false:dll
}
else
{
options.GenerateExecutable = false;//true为可执行exe,false:dll
}
return provider.CompileAssemblyFromDom(options, unit);//编译程序集
}
}
}
HelloWorld
示例二
using System;
using System.Data;
using System.Configuration;
using System.Text;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Reflection; namespace Practice.Common
{
/// <summary>
/// 本类用来将字符串转为可执行文本并执行
/// </summary>
public class DynamicEvaluator
{
#region 构造函数 /// <summary>
/// 可执行串的构造函数
/// </summary>
/// <param name="items">
/// 可执行字符串数组
/// </param>
public DynamicEvaluator(EvaluatorItem[] items)
{
ConstructEvaluator(items); //调用解析字符串构造函数进行解析
} /// <summary>
/// 可执行串的构造函数
/// </summary>
/// <param name="returnType">返回值类型</param>
/// <param name="expression">执行表达式</param>
/// <param name="name">执行字符串名称</param>
public DynamicEvaluator(Type returnType, string expression, string name)
{
//创建可执行字符串数组
EvaluatorItem[] items = { new EvaluatorItem(returnType, expression, name) };
ConstructEvaluator(items); //调用解析字符串构造函数进行解析
} /// <summary>
/// 可执行串的构造函数
/// </summary>
/// <param name="item">可执行字符串项</param>
public DynamicEvaluator(EvaluatorItem item)
{
EvaluatorItem[] items = { item };//将可执行字符串项转为可执行字符串项数组
ConstructEvaluator(items); //调用解析字符串构造函数进行解析
} /// <summary>
/// 解析字符串构造函数
/// </summary>
/// <param name="items">待解析字符串数组</param>
private void ConstructEvaluator(EvaluatorItem[] items)
{
//创建C#编译器实例
CodeDomProvider provider = CodeDomProvider.CreateProvider("C#"); //过时了
//ICodeCompiler comp = provider.CreateCompiler(); //编译器的传入参数
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll"); //添加程序集 system.dll 的引用
cp.ReferencedAssemblies.Add("system.data.dll"); //添加程序集 system.data.dll 的引用
cp.ReferencedAssemblies.Add("system.xml.dll"); //添加程序集 system.xml.dll 的引用
cp.GenerateExecutable = false; //不生成可执行文件
cp.GenerateInMemory = true; //在内存中运行 StringBuilder code = new StringBuilder(); //创建代码串
/*
* 添加常见且必须的引用字符串
*/
code.Append("using System; ");
code.Append("using System.Xml; ");
code.Append("using System.Collections.Generic; "); code.Append("namespace Flow { "); //生成代码的命名空间为EvalGuy,和本代码一样 code.Append(" public class _Evaluator { "); //产生 _Evaluator 类,所有可执行代码均在此类中运行
foreach (EvaluatorItem item in items) //遍历每一个可执行字符串项
{
code.AppendFormat(" public {0} {1}() ", //添加定义公共函数代码
item.ReturnType.Name, //函数返回值为可执行字符串项中定义的返回值类型
item.Name); //函数名称为可执行字符串项中定义的执行字符串名称
code.Append("{ "); //添加函数开始括号 code.AppendFormat("return ({0});", item.Expression);//添加函数体,返回可执行字符串项中定义的表达式的值
code.Append("}"); //添加函数结束括号
}
code.Append("} }"); //添加类结束和命名空间结束括号 //得到编译器实例的返回结果
CompilerResults cr = provider.CompileAssemblyFromSource(cp, code.ToString());//comp if (cr.Errors.HasErrors) //如果有错误
{
StringBuilder error = new StringBuilder(); //创建错误信息字符串
error.Append("编译有错误的表达式: "); //添加错误文本
foreach (CompilerError err in cr.Errors) //遍历每一个出现的编译错误
{
error.AppendFormat("{0}", err.ErrorText); //添加进错误文本,每个错误后换行
}
throw new Exception("编译错误: " + error.ToString());//抛出异常
}
Assembly a = cr.CompiledAssembly; //获取编译器实例的程序集
_Compiled = a.CreateInstance("Flow._Evaluator"); //通过程序集查找并声明的实例
}
#endregion
#region 公有成员
/// <summary>
/// 执行字符串并返回整型值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
public int EvaluateInt(string name)
{
return (int)Evaluate(name);
}
/// <summary>
/// 执行字符串并返回双精度值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
public double EvaluateDouble(string name)
{
return (double)Evaluate(name);
}
/// <summary>
/// 执行字符串并返回长整型数值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
public long EvaluateLong(string name)
{
return (long)Evaluate(name);
}
/// <summary>
/// 执行字符串并返回十进制数值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
public decimal EvaluateDecimal(string name)
{
return (decimal)Evaluate(name);
}
/// <summary>
/// 执行字符串并返回字符串型值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
public string EvaluateString(string name)
{
return (string)Evaluate(name);
}
/// <summary>
/// 执行字符串并返回布尔型值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
public bool EvaluateBool(string name)
{
return (bool)Evaluate(name);
}
/// <summary>
/// 执行字符串并返 object 型值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
public object Evaluate(string name)
{
MethodInfo mi = _Compiled.GetType().GetMethod(name);//获取 _Compiled 所属类型中名称为 name 的方法的引用
return mi.Invoke(_Compiled, null); //执行 mi 所引用的方法
}
#endregion
#region 静态成员
/// <summary>
/// 执行表达式并返回整型值
/// </summary>
/// <param name="code">要执行的表达式</param>
/// <returns>运算结果</returns>
static public int EvaluateToInteger(string code)
{
DynamicEvaluator eval = new DynamicEvaluator(typeof(int), code, staticMethodName);//生成 Evaluator 类的对像
return (int)eval.Evaluate(staticMethodName); //执行并返回整型数据
}
/// <summary>
/// 执行表达式并返回双精度值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
static public double EvaluateToDouble(string code)
{
DynamicEvaluator eval = new DynamicEvaluator(typeof(double), code, staticMethodName);//生成 Evaluator 类的对像
return (double)eval.Evaluate(staticMethodName);
}
/// <summary>
/// 执行表达式并返回长整型数值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
static public long EvaluateToLong(string code)
{
DynamicEvaluator eval = new DynamicEvaluator(typeof(long), code, staticMethodName);//生成 Evaluator 类的对像
return (long)eval.Evaluate(staticMethodName);
}
/// <summary>
/// 执行表达式并返回十进制数值
/// </summary>
/// <param name="name">执行字符串名称</param>
/// <returns>执行结果</returns>
static public decimal EvaluateToDecimal(string code)
{
DynamicEvaluator eval = new DynamicEvaluator(typeof(decimal), code, staticMethodName);//生成 Evaluator 类的对像
return (decimal)eval.Evaluate(staticMethodName);
}
/// <summary>
/// 执行表达式并返回字符串型值
/// </summary>
/// <param name="code">要执行的表达式</param>
/// <returns>运算结果</returns>
static public string EvaluateToString(string code)
{
DynamicEvaluator eval = new DynamicEvaluator(typeof(string), code, staticMethodName);//生成 Evaluator 类的对像
return (string)eval.Evaluate(staticMethodName); //执行并返回字符串型数据
}
/// <summary>
/// 执行表达式并返回布尔型值
/// </summary>
/// <param name="code">要执行的表达式</param>
/// <returns>运算结果</returns>
static public bool EvaluateToBool(string code)
{
DynamicEvaluator eval = new DynamicEvaluator(typeof(bool), code, staticMethodName);//生成 Evaluator 类的对像
return (bool)eval.Evaluate(staticMethodName); //执行并返回布尔型数据
}
/// <summary>
/// 执行表达式并返回 object 型值
/// </summary>
/// <param name="code">要执行的表达式</param>
/// <returns>运算结果</returns>
static public object EvaluateToObject(string code)
{
DynamicEvaluator eval = new DynamicEvaluator(typeof(object), code, staticMethodName);//生成 Evaluator 类的对像
return eval.Evaluate(staticMethodName); //执行并返回 object 型数据
}
#endregion
#region 私有成员
/// <summary>
/// 静态方法的执行字符串名称
/// </summary>
private const string staticMethodName = "__foo";
/// <summary>
/// 用于动态引用生成的类,执行其内部包含的可执行字符串
/// </summary>
object _Compiled = null;
#endregion
} /// <summary>
/// 可执行字符串项(即一条可执行字符串)
/// </summary>
public class EvaluatorItem
{
/// <summary>
/// 返回值类型
/// </summary>
public Type ReturnType;
/// <summary>
/// 执行表达式
/// </summary>
public string Expression;
/// <summary>
/// 执行字符串名称
/// </summary>
public string Name;
/// <summary>
/// 可执行字符串项构造函数
/// </summary>
/// <param name="returnType">返回值类型</param>
/// <param name="expression">执行表达式</param>
/// <param name="name">执行字符串名称</param>
public EvaluatorItem(Type returnType, string expression, string name)
{
ReturnType = returnType;
Expression = expression;
Name = name;
}
}
}
动态编译字符串示例
资料:
类库:
https://msdn.microsoft.com/zh-cn/library/system.codedom.compiler(v=vs.110).aspx
示例文档:
https://msdn.microsoft.com/zh-cn/library/650ax5cx(v=vs.110).aspx
快速参考:
https://msdn.microsoft.com/zh-cn/library/f1dfsbhc(v=vs.110).aspx
博客
http://www.cnblogs.com/whitewolf/archive/2010/06/19/1760708.html
工具:
C#>VB:
http://www.dotnetspider.com/convert/CSharp-To-Vb.aspx
.Net拾忆:CodeDom动态源代码生成器和编译器的更多相关文章
- .Net拾忆:从List去除重复-拾忆集合
方法1: private static List<int> DistinctList(List<int> list) {//去除重复 HashSet<int> ha ...
- .NET 5 源代码生成器——MediatR——CQRS
在这篇文章中,我们将探索如何使用.NET 5中的新source generator特性,使用MediatR库和CQRS模式自动为系统生成API. 中介者模式 中介模式是在应用程序中解耦模块的一种方式. ...
- 基于SSM风格的Java源代码生成器
一.序言 UCode Cms 是一款Maven版的Java源代码生成器,是快速构建项目的利器.代码生成器模块属于可拆卸模块,即按需引入.代码生成器生成SSM(Spring.SpringBoot.Myb ...
- 【摸鱼神器】基于SSM风格的Java源代码生成器 单表生成 一对一、一对多、多对多连接查询生成
一.序言 UCode Cms 是一款Maven版的Java源代码生成器,是快速构建项目的利器.代码生成器模块属于可拆卸模块,即按需引入.代码生成器生成SSM(Spring.SpringBoot.Myb ...
- 使用CodeDom动态生成类型
.NET 3.5的时候加入了匿名类型这个特性,我们可以直接使用 new {name="abc"} 来直接生成一个对象.这个特性现在应用的地方很多,比如dapper的查询参数都是用匿 ...
- #ifdef,#else,#endif,#if 拾忆
预处理就是在进行编译的第一遍词法扫描和语法分析之前所作的工作.说白了,就是对源文件进行编译前,先对预处理部分进行处理,然后对处理后的代码进行编译.这样做的好处是,经过处理后的代码,将会变的很精短. ...
- 使用CodeDOM动态编译一个字符串表达式
由于程序需要,计算的表达式使用字符串传输,这样对运算造成了影响.在程序中直接执行这段表达式可以得到值, 但是使用字符串就没有办法运算了, 所以想到用CodeDOM将这段字符串拼接在代码中编译 类似st ...
- 利用CodeDom 动态执行条件表达式
在实际需求遇到需要根据不同条件,去指定不同的不同的审批人.起初的需求倒很简单,明确是当金额 >=500000 , 可变的就是500000这个数额. 当时为了防止可能产生的变化.特意搞了 条 ...
- C#使用CodeDom动态加载cs文件
public static object Create(string path) { var provOptions = new Dictionary<string, string>(); ...
随机推荐
- Mybatis 不同使用方式
前言 工作这么多年,ORM框架一直选择Mybatis框架. Mybatis的使用方式也一直在变,总体来说是越来越简单.写篇文章对各使用方式做个总结... 正文 一.Mybatis典型用法 1. 正常执 ...
- Will vs Be Going To vs Present Continuous: Talk About the Future in English
https://www.youtube.com/watch?v=UISiuiPd_FY will 说话的当下决定的将来要做什么,in the moment be going to 有意图去做,但没有计 ...
- 新浪广告交易平台(SAX)DSP手册
新浪广告交易平台(SAX)DSP手册 http://amp.ad.sina.com.cn/sax/doc/zh-CN/xhtml/index.xhtml 新浪广告交易平台(SAX)DSP手册 版权 © ...
- Android+Tomcat通过http获取本机服务器资源
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...
- [math] 绘制空间几何体的直观图
这么多年,一直凭着从天而降的神来之灵感画着立体图. 而今才知道在二维平面上绘制空间几何体的直观图也是有方法的.叫做“画法几何” 1. 斜二测图 就是倾斜y轴,使y轴与x轴成45度的夹角.见: http ...
- 什么是渲染目标(render target)&& 渲染到纹理(Render To Texture, RTT)详解
渲染到纹理(Render To Texture, RTT)详解 RTT是现在很多特效里面都会用到的一项很基本的技术,实现起来很简单,也很重要.但是让人不解的是网上搜索了半天只找到很少的文章说这个事儿, ...
- python知识点杂记
1. Python没有 ++, --操作. 2. Join比+快:tuple比list快 3. Dict的key是区分大小写的 4. 参数顺序:无默认值参数,有默认值参数,tuple,dict 5. ...
- Java之旅_面向对象_抽象类
参考并摘自:http://www.runoob.com/java/java-abstraction.html Java抽象类: 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有 ...
- Python开发【笔记】:PEP 8 编码规范
PEP 8 编码规范 https://bk.tencent.com/document/bkrule/040101.pdf ...
- 【Python爬虫】Requests库的基本使用
Requests库的基本使用 阅读目录 基本的GET请求 带参数的GET请求 解析Json 获取二进制数据 添加headers 基本的POST请求 response属性 文件上传 获取cookie 会 ...