【又见好博文】动态编译

     动态编译的好处其实有不少,可是我发现不少人其实没有真正理解或者没有灵活运用动态编译,使得这么强大的一个功能变成了鸡肋。在我本身使用的工具库中有不少地方都使用了动态编译,之后我会慢慢把工具库中的代码都发布出来,因此先把动态编译的相关知识点整理了一下c#

什么是动态编译?框架

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

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

Exec('select * from [table]')

或者Javascript中的性能

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

1.为了比较方便的解决一些难题
  例如,计算一个公式的字符串的值"2+3*(4-1)/5%7"
  要计算这个公式的值,把他编译后直接输出无疑是最简单有效的方法,就好比这样spa

//formula = 2 + 3 * (4 - 1) / 5 % 7
public 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);
}

 上面说的这种状况是最基本的一种状况,也是最容易理解的一种状况(就我我的来讲是不推荐的,由于编译一个程序集自己对资源的消耗是很大了,这种公式编译后的对象正常状况下是没法卸载的,若是动态编译只为了使用一次是极为不明智的)code

  2.为了程序的性能更好orm

  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);//记录命名空间,由于不想重复因此使用了HashSet
                compilerParameters.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;
                }
            }
        }
    }
}

再来就是调用部分的代码了,仍是刚才那个计算的例子

using System;
namespace blqw.DynamicCompile_Demo
{
    public class Program
    {
        static void Main(string[] args)
        {
            decimal val = Calculate("2 + 3 * (4 - 1) / 5 % 7");
            if (val == (decimal)(2 + 3 * (4 - 1) / 5 % 7))
            {
                Console.WriteLine(val);
            }
            else
            {
                Console.WriteLine("错误");
            }
        }
        public static decimal Calculate(string formula)
        {
            string code = @"
                public class Class1
                {
                    public static decimal GetValue()
                    {
                        return (decimal)(" + formula + @");
                    }
                }
            ";
            //第二个参数就是这个类中全部用到的类型,包括隐式类型
            Type type = DynamicCompile_1.CompileAssembly(code, typeof(decimal)).GetType("Class1");
            return (decimal)type.GetMethod("GetValue").Invoke(null, null);
        }
    }
}

运行后直接就能够看到效果了,全部代码都在这里了就不提供下载了哈

相关文章
相关标签/搜索