- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详细介绍.NET中的动态编译技术由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
代码的动态编译并执行是一个.NET平台提供给我们的很强大的工具用以灵活扩展(当然是面对内部开发人员)复杂而无法估算的逻辑,并通过一些额外的代码来扩展我们已有 的应用程序。这在很大程度上给我们提供了另外一种扩展的方式(当然这并不能算是严格意义上的扩展,但至少为我们提供了一种思路).
动态代码执行可以应用在诸如模板生成,外加逻辑扩展等一些场合。一个简单的例子,为了网站那的响应速度,HTML静态页面往往是我们最好的选择,但基于数据驱动的网站往往又很难用静态页面实现,那么将动态页面生成html的工作或许就是一个很好的应用场合。另外,对于一些模板的套用,我们同样可以用它来做。另外这本身也是插件编写的方式.
最基本的动态编译 。
.Net为我们提供了很强大的支持来实现这一切我们可以去做的基础,主要应用的两个命名空间是:System.CodeDom.Compiler和Microsoft.CSharp或Microsoft.VisualBasic。另外还需要用到反射来动态执行你的代码。动态编译并执行代码的原理其实在于将提供的源代码交予CSharpCodeProvider来执行编译(其实和CSC没什么两样),如果没有任何编译错误,生成的IL代码会被编译成DLL存放于于内存并加载在某个应用程序域(默认为当前)内并通过反射的方式来调用其某个方法或者触发某个事件等。之所以说它是插件编写的一种方式也正是因为与此,我们可以通过预先定义好的借口来组织和扩展我们的程序并将其交还给主程序去触发。一个基本的动态编译并执行代码的步骤包括:
· 将要被编译和执行的代码读入并以字符串方式保存 。
· 声明CSharpCodeProvider对象实例 。
· 调用CSharpCodeProvider实例的CompileAssemblyFromSource方法编译 。
· 用反射生成被生成对象的实例(Assembly.CreateInstance) 。
· 调用其方法 。
以下代码片段包含了完整的编译和执行过程:
。
//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,
。
需要解释的是,这里我们在传递编译参数时设置了GenerateInMemory为true,这表明生成的DLL会被加载在内存中(随后被默认引用入当前应用程序域)。在调用GetTime方法时我们需要加入参数,传递object类型的数组并通过Reflection的InvokeMember来调用。在创建生成的Assembly中的对象实例时,需要注意用到的命名空间是你输入代码的真实命名空间。以下是我们输入的测试代码(为了方便,所有的代码都在外部输入,动态执行时不做调整):
。
using System,
。
namespace Dynamicly 。
{ 。
public class HelloWorld 。
{ 。
public string GetTime(string strName) 。
{ 。
return "Welcome " + strName + ", Check in at " + System.DateTime.Now.ToString(),
} 。
} 。
} 。
。
运行附件中提供的程序,可以很容易得到一下结果:
改进的执行过程 。
现在一切看起来很好,我们可以编译代码并把代码加载到当前应用程序域中来参与我们的活动,但你是否想过去卸载掉这段程序呢?更好的去控制程序呢?另外,当你运行这个程序很多遍的时候,你会发现占用内存很大,而且每次执行都会增大内存使用。是否需要来解决这个问题呢?当然需要,否则你会发现这个东西根本没用,我需要执行的一些大的应用会让我的服务器crzay,不堪重负而疯掉的.
要解决这个问题我们需要来了解一下应用程序域。.NET Application Domain是.NET提供的运行和承载一个活动的进程(Process)的容器,它将这个进程运行所需的代码和数据,隔离到一个小的范围内,称为Application Domain。当一个应用程序运行时,Application Domains将所有的程序集/组件集加载到当前的应用程序域中,并根据需要来调用。而对于动态生成的代码/程序集,我们看起来好像并没有办法去管理它。其实不然,我们可以用Application Domain提供的管理程序集的办法来动态加载和移除Assemblies来达到我们的提高性能的目的。具体怎么做呢,在前边的基础上增加以下步骤:
· 创建另外一个Application Domain 。
· 动态创建(编译)代码并保存到磁盘 。
· 创建一个公共的远程调用接口 。
· 创建远程调用接口的实例。并通过这个接口来访问其方法.
换句话来讲就是将对象加载到另外一个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 + "\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"),
。
对于客户端的输入程序,我们需要继承于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(),
} 。
} 。
} 。
这样,你可以通过适时的编译,加载和卸载程序集来保证你的程序始终处于一个可控消耗的过程,并且达到了动态编译的目的,而且因为在不同的应用程序域中,让你的本身的程序更加安全和健壮.
最后此篇关于详细介绍.NET中的动态编译技术的文章就讲到这里了,如果你想了解更多关于详细介绍.NET中的动态编译技术的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
创建使用.NET框架的asp.net页面时,访问该页面的客户端是否需要在其计算机上安装.NET框架? IE。用户访问www.fakesite.com/default.aspx,如果他们没有安装框架,他
我阅读了很多不同的博客和 StackOverflow 问题,试图找到我的问题的答案,但最后我找不到任何东西,所以我想自己问这个问题。 我正在构建一个应用程序,其中有一个长时间运行的工作线程,它执行一些
已锁定。这个问题及其答案是locked因为这个问题是题外话,但却具有历史意义。目前不接受新的答案或互动。 我一直想知道为什么微软为这样一个伟大的平台选择了一个如此奇怪的、对搜索引擎不友好的名称。他们就
.Net Framework .Net .NET Standard的区别 1、.NET Framework 在未来.NET Framework或许成为过去时,目前还是有很多地方在使用的。这一套
如果有选择的话,您会走哪条路? ASP.NET Webforms + ASP.NET AJAX 或 ASP.NET MVC + JavaScript Framework of your Choice
我有一个 Web 服务,它通过专用连接通过 https 使用第三方 Web 服务,我应用了 ServicePointManager.ServerCertificateValidationCallbac
为什么我应该选择ASP.NET Web Application (.NET Framework)而不是ASP.NET Core Web Application (.NET Framework)? 我在
我在网络上没有找到任何关于包含 .NET Standard、.NET Core 和 .NET Framework 项目的 .NET 解决方案的公认命名约定。 就我而言,我们在 .NET 框架项目中有以
.NET Compact 是 .NET 的完美子集吗? 假设我考虑了屏幕大小和其他限制并避免了 .NET Compact 不支持的类和方法,或者 .NET Compact 是一个不同且不兼容的 GUI
我已经阅读了所有我能找到的关于 connectionManagement 中的 maxconnection 设置的文章:即 http://support.microsoft.com/kb/821268
我现在正在使用asp.net mvc,想知道使用内置的Json或 Json.Net哪个是更好的选择,但我不确定一个人是否比另一个人有优势。 另外,如果我确实选择沿用Json.Net的路线,那么我应该选
在 Visual Studio 中,您至少可以创建三种不同类型的类库: 类库(.NET Framework) 类库(.NET 标准) 类库(.NET Core) 虽然第一个是我们多年来一直使用的,但我
.NET 和 ASP.NET 之间有什么区别?它们有什么关系? 最佳答案 ASP.Net 基于 .Net 框架构建,提供有关 Web 开发的附加功能。 你可以去看看wikipedia article
在安装更高版本(3.0)之前,我需要安装.net框架1.1和2.0吗?或者单独安装 3.0 框架就足够了,并为在早期框架版本上编写的软件提供支持?谢谢 ,丽然 最佳答案 不,您不必安装以前的框架。 我
我正在开发一个项目,人们可以“更新”类别,例如更改类别的名称。我收到以下消息 This is called after clicking update 按钮 with the SQL statemen
.NET 类 System.Net.CookieContainer 线程安全吗? --更新:交 key 答复-- 是否有任何方法可以确保异步请求期间修改的变量(即 HttpWebRequest.Coo
我正在使用 JScript.NET 在我编写的 C# WinForms 应用程序中编写脚本。它工作得很好,但我只是尝试在脚本中放置一些异常处理,但我无法弄清楚如何判断我的 C# 代码抛出了哪种类型的异
我需要你的帮助, 比如我有一个小数类型的变量,我想这样取整。 例如 3.0 = 3 3.1 = 4 3.2 = 4 3.3 = 4 3.4 = 4 3.5 = 4 3.6 = 4 3.7 = 4 3.
我使用过这样的代码:http://msdn.microsoft.com/en-us/library/dw70f090.aspx在 ASP.NET 中工作之前访问数据库(2-3 年前)。我没有意识到我正
自 ConfigurationManager .NET Standard 中不存在,检索正在执行的程序集的应用程序设置的最佳方法是什么,无论是 web.config或 appSettings.{env
我是一名优秀的程序员,十分优秀!