.NET 动态编译
换句话来讲就是将对象加载到另外一个AppDomain中并通过远程调用的方法来调用。所谓远程调用其实也就是跨应用程序域调用,所以这个对象(动态代码)必须继承于MarshalByRefObject类。为了复用,这个接口被单独提到一个工程中,并提供一个工厂来简化每次的调用操作: 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(); } } } 接下来在原来基础上需要修改的是: · 将编译成的DLL保存到磁盘中。 · 创建另外的AppDomain。 · 获得IRemoteInterface接口的引用。(将生成的DLL加载到额外的AppDomain) · 调用InvokeMethod方法来远程调用。 · 可以通过AppDomain.Unload()方法卸载程序集。 以下是完整的代码,演示了如何应用这一方案。 //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 + "rnLine: " + 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"); 对于客户端的输入程序,我们需要继承于MarshalByRefObject类和IRemoteInterface接口,并添加对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(); } } } 这样,你可以通过适时的编译,加载和卸载程序集来保证你的程序始终处于一个可控消耗的过程,并且达到了动态编译的目的,而且因为在不同的应用程序域中,让你的本身的程序更加安全和健壮。示例代码下载: (编辑:焦作站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |