<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

        .NET 動(dòng)態(tài)編譯

        來源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 22:44:22
        文檔

        .NET 動(dòng)態(tài)編譯

        .NET 動(dòng)態(tài)編譯:這在很大程度上給我們提供了另外一種擴(kuò)展的方式(當(dāng)然這并不能算是嚴(yán)格意義上的擴(kuò)展,但至少為我們提供了一種思路)。 動(dòng)態(tài)代碼執(zhí)行可以應(yīng)用在諸如模板生成,外加邏輯擴(kuò)展等一些場(chǎng)合。一個(gè)簡(jiǎn)單的例子,為了網(wǎng)站那的響應(yīng)速度,HTML靜態(tài)頁(yè)面往往是我們最好的選
        推薦度:
        導(dǎo)讀.NET 動(dòng)態(tài)編譯:這在很大程度上給我們提供了另外一種擴(kuò)展的方式(當(dāng)然這并不能算是嚴(yán)格意義上的擴(kuò)展,但至少為我們提供了一種思路)。 動(dòng)態(tài)代碼執(zhí)行可以應(yīng)用在諸如模板生成,外加邏輯擴(kuò)展等一些場(chǎng)合。一個(gè)簡(jiǎn)單的例子,為了網(wǎng)站那的響應(yīng)速度,HTML靜態(tài)頁(yè)面往往是我們最好的選

        這在很大程度上給我們提供了另外一種擴(kuò)展的方式(當(dāng)然這并不能算是嚴(yán)格意義上的擴(kuò)展,但至少為我們提供了一種思路)。

        動(dòng)態(tài)代碼執(zhí)行可以應(yīng)用在諸如模板生成,外加邏輯擴(kuò)展等一些場(chǎng)合。一個(gè)簡(jiǎn)單的例子,為了網(wǎng)站那的響應(yīng)速度,HTML靜態(tài)頁(yè)面往往是我們最好的選擇,但基于數(shù)據(jù)驅(qū)動(dòng)的網(wǎng)站往往又很難用靜態(tài)頁(yè)面實(shí)現(xiàn),那么將動(dòng)態(tài)頁(yè)面生成html的工作或許就是一個(gè)很好的應(yīng)用場(chǎng)合。另外,對(duì)于一些模板的套用,我們同樣可以用它來做。另外這本身也是插件編寫的方式。

         

        最基本的動(dòng)態(tài)編譯

         

        .Net為我們提供了很強(qiáng)大的支持來實(shí)現(xiàn)這一切我們可以去做的基礎(chǔ),主要應(yīng)用的兩個(gè)命名空間是:System.CodeDom.Compiler和Microsoft.CSharp或Microsoft.VisualBasic。另外還需要用到反射來動(dòng)態(tài)執(zhí)行你的代碼。動(dòng)態(tài)編譯并執(zhí)行代碼的原理其實(shí)在于將提供的源代碼交予CSharpCodeProvider來執(zhí)行編譯(其實(shí)和CSC沒什么兩樣),如果沒有任何編譯錯(cuò)誤,生成的IL代碼會(huì)被編譯成DLL存放于于內(nèi)存并加載在某個(gè)應(yīng)用程序域(默認(rèn)為當(dāng)前)內(nèi)并通過反射的方式來調(diào)用其某個(gè)方法或者觸發(fā)某個(gè)事件等。之所以說它是插件編寫的一種方式也正是因?yàn)榕c此,我們可以通過預(yù)先定義好的借口來組織和擴(kuò)展我們的程序并將其交還給主程序去觸發(fā)。一個(gè)基本的動(dòng)態(tài)編譯并執(zhí)行代碼的步驟包括:

        ·         將要被編譯和執(zhí)行的代碼讀入并以字符串方式保存

        ·         聲明CSharpCodeProvider對(duì)象實(shí)例

        ·         調(diào)用CSharpCodeProvider實(shí)例的CompileAssemblyFromSource方法編譯

        ·         用反射生成被生成對(duì)象的實(shí)例(Assembly.CreateInstance)

        ·         調(diào)用其方法

        以下代碼片段包含了完整的編譯和執(zhí)行過程:

        //get the code to compile

        string strSourceCode = this.txtSource.Text;

         

        // 1.Create a new CSharpCodePrivoder instance

        CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();

         

        // 2.Sets the runtime compiling parameters by crating a new CompilerParameters instance

        CompilerParameters objCompilerParameters = new CompilerParameters();

        objCompilerParameters.ReferencedAssemblies.Add("System.dll");

        objCompilerParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");

        objCompilerParameters.GenerateInMemory = true;

         

        // 3.CompilerResults: Complile the code snippet by calling a method from the provider

        CompilerResults cr = objCSharpCodePrivoder.CompileAssemblyFromSource(objCompilerParameters, strSourceCode);

         

        if (cr.Errors.HasErrors)

        {

            string strErrorMsg = cr.Errors.Count.ToString() + " Errors:";

         

            for (int x = 0; x < cr.Errors.Count; x++)

            {

                strErrorMsg = strErrorMsg + "\r\nLine: " +

                             cr.Errors[x].Line.ToString() + " - " +

                             cr.Errors[x].ErrorText;

            }

         

            this.txtResult.Text = strErrorMsg;

            MessageBox.Show("There were build erros, please modify your code.", "Compiling Error");

         

            return;

        }

         

        // 4. Invoke the method by using Reflection

        Assembly objAssembly = cr.CompiledAssembly;

        object objClass = objAssembly.CreateInstance("Dynamicly.HelloWorld");

        if (objClass == null)

        {

            this.txtResult.Text = "Error: " + "Couldn't load class.";

            return;

        }

         

        object[] objCodeParms = new object[1];

        objCodeParms[0] = "Allan.";

         

        string strResult = (string)objClass.GetType().InvokeMember(

                   "GetTime", BindingFlags.InvokeMethod, null, objClass, objCodeParms);

         

        this.txtResult.Text = strResult;

        需要解釋的是,這里我們?cè)趥鬟f編譯參數(shù)時(shí)設(shè)置了GenerateInMemory為true,這表明生成的DLL會(huì)被加載在內(nèi)存中(隨后被默認(rèn)引用入當(dāng)前應(yīng)用程序域)。在調(diào)用GetTime方法時(shí)我們需要加入?yún)?shù),傳遞object類型的數(shù)組并通過Reflection的InvokeMember來調(diào)用。在創(chuàng)建生成的Assembly中的對(duì)象實(shí)例時(shí),需要注意用到的命名空間是你輸入代碼的真實(shí)命名空間。以下是我們輸入的測(cè)試代碼(為了方便,所有的代碼都在外部輸入,動(dòng)態(tài)執(zhí)行時(shí)不做調(diào)整):

        using System;

         

        namespace Dynamicly

        {

            public class HelloWorld

            {

                public string GetTime(string strName)

                {

                    return  "Welcome " + strName + ", Check in at " + System.DateTime.Now.ToString();

                }

            }

        }

        運(yùn)行附件中提供的程序,可以很容易得到一下結(jié)果:

         

        改進(jìn)的執(zhí)行過程

         

        現(xiàn)在一切看起來很好,我們可以編譯代碼并把代碼加載到當(dāng)前應(yīng)用程序域中來參與我們的活動(dòng),但你是否想過去卸載掉這段程序呢?更好的去控制程序呢?另外,當(dāng)你運(yùn)行這個(gè)程序很多遍的時(shí)候,你會(huì)發(fā)現(xiàn)占用內(nèi)存很大,而且每次執(zhí)行都會(huì)增大內(nèi)存使用。是否需要來解決這個(gè)問題呢?當(dāng)然需要,否則你會(huì)發(fā)現(xiàn)這個(gè)東西根本沒用,我需要執(zhí)行的一些大的應(yīng)用會(huì)讓我的服務(wù)器crzay,不堪重負(fù)而瘋掉的。

        要解決這個(gè)問題我們需要來了解一下應(yīng)用程序域。.NET Application Domain.NET提供的運(yùn)行和承載一個(gè)活動(dòng)的進(jìn)程(Process)的容器,它將這個(gè)進(jìn)程運(yùn)行所需的代碼和數(shù)據(jù),隔離到一個(gè)小的范圍內(nèi),稱為Application Domain。當(dāng)一個(gè)應(yīng)用程序運(yùn)行時(shí),Application Domains將所有的程序集/組件集加載到當(dāng)前的應(yīng)用程序域中,并根據(jù)需要來調(diào)用。而對(duì)于動(dòng)態(tài)生成的代碼/程序集,我們看起來好像并沒有辦法去管理它。其實(shí)不然,我們可以用Application Domain提供的管理程序集的辦法來動(dòng)態(tài)加載和移除Assemblies來達(dá)到我們的提高性能的目的。具體怎么做呢,在前邊的基礎(chǔ)上增加以下步驟:

        ·         創(chuàng)建另外一個(gè)Application Domain

        ·         動(dòng)態(tài)創(chuàng)建(編譯)代碼并保存到磁盤

        ·         創(chuàng)建一個(gè)公共的遠(yuǎn)程調(diào)用接口

        ·         創(chuàng)建遠(yuǎn)程調(diào)用接口的實(shí)例。并通過這個(gè)接口來訪問其方法。

        換句話來講就是將對(duì)象加載到另外一個(gè)AppDomain中并通過遠(yuǎn)程調(diào)用的方法來調(diào)用。所謂遠(yuǎn)程調(diào)用其實(shí)也就是跨應(yīng)用程序域調(diào)用,所以這個(gè)對(duì)象(動(dòng)態(tài)代碼)必須繼承于MarshalByRefObject類。為了復(fù)用,這個(gè)接口被單獨(dú)提到一個(gè)工程中,并提供一個(gè)工廠來簡(jiǎn)化每次的調(diào)用操作:

        using System;

        using System.Collections.Generic;

        using System.Linq;

        using System.Text;

        using System.Reflection;

         

        namespace RemoteAccess

        {

            /// <summary>

                  /// Interface that can be run over the remote AppDomain boundary.

                  /// </summary>

                  public interface IRemoteInterface

                  {

                           object Invoke(string lcMethod,object[] Parameters);

                  }

         

                  /// <summary>

                  /// Factory class to create objects exposing IRemoteInterface

                  /// </summary>

                  public class RemoteLoaderFactory : MarshalByRefObject

                  {

                           private const BindingFlags bfi = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;

         

                           public RemoteLoaderFactory() {}

         

                           public IRemoteInterface Create( string assemblyFile, string typeName, object[] constructArgs )

                           {

                                     return (IRemoteInterface) Activator.CreateInstanceFrom(

                                              assemblyFile, typeName, false, bfi, null, constructArgs,

                                              null, null, null ).Unwrap();

                           }

                  }       

        }

         

        接下來在原來基礎(chǔ)上需要修改的是:

        ·         將編譯成的DLL保存到磁盤中。

        ·         創(chuàng)建另外的AppDomain

        ·         獲得IRemoteInterface接口的引用。(將生成的DLL加載到額外的AppDomain

        ·         調(diào)用InvokeMethod方法來遠(yuǎn)程調(diào)用。

        ·         可以通過AppDomain.Unload()方法卸載程序集。

        以下是完整的代碼,演示了如何應(yīng)用這一方案。

        //get the code to compile

        string strSourceCode = this.txtSource.Text;

         

        //1. Create an addtional AppDomain

        AppDomainSetup objSetup = new AppDomainSetup();

        objSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

        AppDomain objAppDomain = AppDomain.CreateDomain("MyAppDomain", null, objSetup);

         

        // 1.Create a new CSharpCodePrivoder instance

        CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider();

         

        // 2.Sets the runtime compiling parameters by crating a new CompilerParameters instance

        CompilerParameters objCompilerParameters = new CompilerParameters();

        objCompilerParameters.ReferencedAssemblies.Add("System.dll");

        objCompilerParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");

         

        // Load the remote loader interface

        objCompilerParameters.ReferencedAssemblies.Add("RemoteAccess.dll");

         

        // Load the resulting assembly into memory

        objCompilerParameters.GenerateInMemory = false;

        objCompilerParameters.OutputAssembly = "DynamicalCode.dll";

         

        // 3.CompilerResults: Complile the code snippet by calling a method from the provider

        CompilerResults cr = objCSharpCodePrivoder.CompileAssemblyFromSource(objCompilerParameters, strSourceCode);

         

        if (cr.Errors.HasErrors)

        {

            string strErrorMsg = cr.Errors.Count.ToString() + " Errors:";

         

            for (int x = 0; x < cr.Errors.Count; x++)

            {

                strErrorMsg = strErrorMsg + "\r\nLine: " +

                             cr.Errors[x].Line.ToString() + " - " +

                             cr.Errors[x].ErrorText;

            }

         

            this.txtResult.Text = strErrorMsg;

            MessageBox.Show("There were build erros, please modify your code.", "Compiling Error");

         

            return;

        }

         

        // 4. Invoke the method by using Reflection

        RemoteLoaderFactory factory = (RemoteLoaderFactory)objAppDomain.CreateInstance("RemoteAccess","RemoteAccess.RemoteLoaderFactory").Unwrap();

         

        // with help of factory, create a real 'LiveClass' instance

        object objObject = factory.Create("DynamicalCode.dll", "Dynamicly.HelloWorld", null);

         

        if (objObject == null)

        {

            this.txtResult.Text = "Error: " + "Couldn't load class.";

            return;

        }

         

        // *** Cast object to remote interface, avoid loading type info

        IRemoteInterface objRemote = (IRemoteInterface)objObject;

         

        object[] objCodeParms = new object[1];

        objCodeParms[0] = "Allan.";

         

        string strResult = (string)objRemote.Invoke("GetTime", objCodeParms);

         

        this.txtResult.Text = strResult;

         

        //Dispose the objects and unload the generated DLLs.

        objRemote = null;

        AppDomain.Unload(objAppDomain);

         

        System.IO.File.Delete("DynamicalCode.dll");

         

        對(duì)于客戶端的輸入程序,我們需要繼承于MarshalByRefObject類和IRemoteInterface接口,并添加對(duì)RemoteAccess程序集的引用。以下為輸入:

        using System;

        using System.Reflection;

        using RemoteAccess;

         

        namespace Dynamicly

        {

            public class HelloWorld : MarshalByRefObject,IRemoteInterface

            {

                public object Invoke(string strMethod,object[] Parameters)

                {

                    return this.GetType().InvokeMember(strMethod, BindingFlags.InvokeMethod,null,this,Parameters);

                }

         

                public string GetTime(string strName)

                {

                    return  "Welcome " + strName + ", Check in at " + System.DateTime.Now.ToString();

                }

            }

        }

         

        這樣,你可以通過適時(shí)的編譯,加載和卸載程序集來保證你的程序始終處于一個(gè)可控消耗的過程,并且達(dá)到了動(dòng)態(tài)編譯的目的,而且因?yàn)樵诓煌膽?yīng)用程序域中,讓你的本身的程序更加安全和健壯。示例代碼下載:
        http://xiazai.jb51.net/200905/yuanma/DynamicCompiler.rar

        聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        .NET 動(dòng)態(tài)編譯

        .NET 動(dòng)態(tài)編譯:這在很大程度上給我們提供了另外一種擴(kuò)展的方式(當(dāng)然這并不能算是嚴(yán)格意義上的擴(kuò)展,但至少為我們提供了一種思路)。 動(dòng)態(tài)代碼執(zhí)行可以應(yīng)用在諸如模板生成,外加邏輯擴(kuò)展等一些場(chǎng)合。一個(gè)簡(jiǎn)單的例子,為了網(wǎng)站那的響應(yīng)速度,HTML靜態(tài)頁(yè)面往往是我們最好的選
        推薦度:
        標(biāo)簽: 動(dòng)態(tài) net 編譯
        • 熱門焦點(diǎn)

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲欧洲精品久久| 亚洲av成人一区二区三区观看在线| 国产成人精品免费视| 国产99在线|亚洲| 国产免费观看青青草原网站| CAOPORN国产精品免费视频| 香蕉蕉亚亚洲aav综合| 成人激情免费视频| 在线观看免费视频网站色| 亚洲国产成人精品无码区在线网站| 免费观看国产精品| 久久精品无码专区免费东京热| 国产成人不卡亚洲精品91| 亚洲国产一区国产亚洲 | 男女免费观看在线爽爽爽视频| 老牛精品亚洲成av人片| 亚洲AV综合色区无码一区| 国产精品va无码免费麻豆| 小草在线看片免费人成视久网| 男男gay做爽爽的视频免费| 亚洲精品**中文毛片| 亚洲人成色7777在线观看不卡 | 成人a毛片视频免费看| 亚洲成人免费电影| 亚洲情综合五月天| 免费a级毛片永久免费| 51在线视频免费观看视频| 一个人看的www免费高清| 性xxxx黑人与亚洲| 久久精品国产精品亚洲艾草网| 亚洲av中文无码| 夭天干天天做天天免费看| 亚欧在线精品免费观看一区| 久久成人永久免费播放| 精品韩国亚洲av无码不卡区| 亚洲嫩草影院在线观看| 亚洲视频在线免费观看| 亚洲午夜国产精品无码| 亚洲日韩在线中文字幕第一页 | 亚洲成av人在线视| 亚洲色欲色欲www在线丝|