Welcome

首页 / 软件开发 / C# / 玩转动态编译(一) 初识

玩转动态编译(一) 初识2014-03-20 cnblogs 冰麟轻武动态编译的好处其实有很多,但是我发现很多人其实没有真正理解或者没有灵活运用动态编译,使得这 么强大的一个功能变成了鸡肋。在我自己使用的工具库中有很多地方都使用了动态编译,以后我会慢慢 把工具库中的代码都发布出来,所以先把动态编译的相关知识点整理了一下

什么是动态编译?

我的个人理解就是,在程序运行期间,将C#代码的字符串编译成为程序集对象,并通过反射该程 序集调用编译后的成员。

比较容易理解的一种解释就是类似于SqlServer中的

Exec("select * from [table]")
或者Javascript中的

var a = eval("(function(){return 1;})")
为什么要使用动态编译?

1.为了比较方便的解决一些难题

例如,计算 一个公式的字符串的值"2+3*(4-1)/5%7"

要计算这个公式的值,把他编译后直接输出无疑是 最简单有效的方法,就比如这样

//formula = 2 + 3 * (4 - 1) / 5 % 7public decimal GetValue(string formula){string code = @"public class Class1{public static decimal GetValue(){return (decimal)(" + formula + @");}}";Type type = 动态编译(code);return (decimal)type.GetMethod("GetValue").Invoke(null, null);}
上面说的这种情况是最基本的一种情况,也是最容易理解的一种情况(就我个人来说是不推荐 的,因为编译一个程序集本身对资源的消耗是很大了,这种公式编译后的对象正常情况下是无法卸载的,如 果动态编译只为了使用一次是极为不明智的)

2.为了程序的性能更好

3,为了程序更灵活

4,为了更好的扩展性

5,.......

ps:2,3,4这些会在下一篇文章中提到,这里先 卖个关子。

怎么使用动态编译

先构造一个方便使用的动态编译的方法

using Microsoft.CSharp;using System;using System.CodeDom.Compiler;using System.Collections.Generic;using System.Reflection;using System.Text;namespace blqw{public class DynamicCompile_1{/// <summary>/// /// </summary>/// <param name="code">需要编译的C#代码</param>/// <param name="usingTypes">编译代码中需要引用的类型</param>/// <returns></returns>public static Assembly CompileAssembly(string code, params Type[] usingTypes){CompilerParameters compilerParameters = new CompilerParameters();//动态编译中使用的参数对象compilerParameters.GenerateExecutable = false;//不需要生成可执行文件compilerParameters.GenerateInMemory = true;//直接在内存中运行//添加需要引用的类型HashSet<string> ns = new HashSet<string>();//用来保存命名空间,这个对象的4.0的,如果是2.0的框架可以使用Dictionary代替foreach (var type in usingTypes){ns.Add("using " + type.Namespace + ";" + Environment.NewLine);//记录命名空间,因为不想重复所以使用了HashSetcompilerParameters.ReferencedAssemblies.Add(type.Module.FullyQualifiedName);//这个相当于引入dll}code = string.Concat(ns) + code;//加入using命名空间的代码,即使原来已经有了也不会报错的//声明编译器using (CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider()){//开始编译CompilerResults cr = objCSharpCodePrivoder.CompileAssemblyFromSource(compilerParameters, code);if (cr.Errors.HasErrors)//如果有错误{StringBuilder sb = new StringBuilder();sb.AppendLine("编译错误:");foreach (CompilerError err in cr.Errors){sb.AppendLine(err.ErrorText);}throw new Exception(sb.ToString());}else{//返回已编译程序集return cr.CompiledAssembly;}}}}}