【又見好博文】動態編譯

     動態編譯的好處其實有不少,可是我發現不少人其實沒有真正理解或者沒有靈活運用動態編譯,使得這麼強大的一個功能變成了雞肋。在我本身使用的工具庫中有不少地方都使用了動態編譯,之後我會慢慢把工具庫中的代碼都發布出來,因此先把動態編譯的相關知識點整理了一下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);
        }
    }
}

運行後直接就能夠看到效果了,全部代碼都在這裏了就不提供下載了哈

相關文章
相關標籤/搜索