中琅软件教程网

首页搜索登录
首页业界网页平面多媒体程序数据库办公工具服务器系统网络安全站长认证壁纸
加入收藏 | 网站地图 | | RSS | WAP
你好,游客 登录 注册 搜索

C#动态编译:执行用户输入的程序代码

[日期:2013-03-23] 作者: 来源: [字体: ]

最近项目需要实现这么一个功能:主程序留有很多切入点(用事件、或者虚方法实现),允许用户在这些切入点输入自定义的处理程序。当主程序执行到这些切入点时执行用户输入的程序代码。这涉及到了C#.net的动态编译功能。

实例代码:

            //设置语言类型,VB or C#

            ZZCompiler.ZZCompiler zzcompiler = new ZZCompiler.ZZCompiler("C#");

            //创建命名空间

            zzcompiler.CreateAppDomain("blue1000");

            //添加程序集文件引用

            zzcompiler.AddAssembly("system.windows.forms.dll");

            //添加命名空间

            zzcompiler.AddNamespace("System.Windows.Forms");

            //执行代码并返回结果,出错返回null

            object result = zzcompiler.ExecuteSection("MessageBox.Show(\"Hello World!\");return 1;", null);

            //错误捕获处理

            if (zzcompiler.bError)

            {

                MessageBox.Show(zzcompiler.cErrorMsg);

            }

            //结束编译并释放

            MessageBox.Show("此对话框后将终止编译进程。");

            zzcompiler.Dispose();

 

涉及到的文件类库:

文件ZZCompiler.cs:

using System;

using System.Collections.Generic;

using System.IO;

using System.Text;

using Microsoft.CSharp;

using Microsoft.VisualBasic;

using System.Reflection;

using System.Runtime.Remoting;

using System.CodeDom.Compiler;

 

using RemoteAccess;

namespace ZZCompiler

{

    public class ZZCompiler:IDisposable

    {

        /// <summary>

        /// 编译器

        /// </summary>

protected ICodeCompiler oCompiler = null;

        /// <summary>

        /// 编译选项

        /// </summary>

protected CompilerParameters oParameters = null;

        /// <summary>

        /// 编译生成的程序集

        /// </summary>

protected Assembly oAssembly = null;

        /// <summary>

        /// 编译结果,包含一些编译后的信息

        /// </summary>

protected CompilerResults oCompiled = null;

        /// <summary>

        /// 输出程序集名称(如果需要将程序集加载到新的应用程序域,需要先将生成的程序集保存到disk)

        /// </summary>

protected string cOutputAssembly = null;

        /// <summary>

        /// 编译必需的命名空间

        /// </summary>

protected string cNamespaces = "";

        /// <summary>

        /// 是否第一次使用

        /// </summary>

protected bool lFirstLoad = true;

        /// <summary>

        /// 

        /// </summary>

public object oObjRef = null;

        /// <summary>

        /// 是否保存处理后的源代码

        /// </summary>

public bool lSaveSourceCode = false;

        /// <summary>

        /// 处理后的可编译的源代码

        /// </summary>

public string cSourceCode = "";

protected int nStartCodeLine = 0;

        /// <summary>

        /// 构造的命名空间名称

        /// </summary>

public string cAssemblyNamespace = "ZZCompile_on_the_fly";

        /// <summary>

        /// 构造的类名称

        /// </summary>

public string cClassName = "ZZ_main";

        /// <summary>

        /// 是否自动添加默认的程序集

        /// </summary>

public bool lDefaultAssemblies = true;

        /// <summary>

        /// (如果需要)新建的应用程序域

        /// </summary>

protected AppDomain oAppDomain = null;

        /// <summary>

        /// 错误信息

        /// </summary>

public string cErrorMsg = "";

public bool bError = false;

 

public string cSupportAssemblyPath = "";

 

public string cScriptingLanguage = "CSharp";

 

public ZZCompiler(string lcLanguage)

{

this.SetLanguage(lcLanguage);

}

        public ZZCompiler() 

{

this.SetLanguage("CSharp");

}

 

 

        /// <summary>

        /// 设置源代码的语言种类

        /// </summary>

        /// <param name="lcLanguage"></param>

public void SetLanguage(string lcLanguage) 

{

this.cScriptingLanguage = lcLanguage;

 

if (this.cScriptingLanguage == "CSharp" || this.cScriptingLanguage == "C#") 

{

this.oCompiler = new CSharpCodeProvider().CreateCompiler();

this.cScriptingLanguage = "CSharp";

}

else if (this.cScriptingLanguage == "VB")

{

this.oCompiler = new VBCodeProvider().CreateCompiler();

}  

// else throw(Exception ex);

 

this.oParameters = new CompilerParameters();

}

 

        /// <summary>

        /// 添加编译时必需的程序集和命名空间

        /// </summary>

        /// <param name="lcAssemblyDll"></param>

        /// <param name="lcNamespace"></param>

public void AddAssembly(string lcAssemblyDll,string lcNamespace) 

{

if (lcAssemblyDll==null && lcNamespace == null) 

{

this.oParameters.ReferencedAssemblies.Clear();

this.cNamespaces = "";

return;

}

 

if (lcAssemblyDll != null)

this.oParameters.ReferencedAssemblies.Add(lcAssemblyDll);

 

if (lcNamespace != null) 

if (this.cScriptingLanguage == "CSharp")

this.cNamespaces = this.cNamespaces + "using " + lcNamespace + ";\r\n";

else

this.cNamespaces = this.cNamespaces + "imports " + lcNamespace + "\r\n";

}

        /// <summary>

        /// 添加编译时必需的程序集

        /// </summary>

        /// <param name="lcAssemblyDll"></param>

public void AddAssembly(string lcAssemblyDll) 

{

this.AddAssembly(lcAssemblyDll,null);

}

        /// <summary>

        /// 添加编译时必需的命名空间

        /// </summary>

        /// <param name="lcNamespace"></param>

public void AddNamespace(string lcNamespace)

{

this.AddAssembly(null,lcNamespace);

}

        /// <summary>

        /// 编译时需要的默认程序集

        /// </summary>

public void AddDefaultAssemblies()

{

this.AddAssembly("System.dll","System");

this.AddNamespace("System.Reflection");

this.AddNamespace("System.IO");

            // 添加其他的默认dll

}

 

 

        /// <summary>

        /// 执行方法

        /// </summary>

        /// <param name="lcCode"></param>

        /// <param name="lcMethodName"></param>

        /// <param name="loParameters"></param>

        /// <returns></returns>

public object ExecuteMethod(string lcCode, string lcMethodName, params object[] loParameters) 

{

 

if (this.oObjRef == null) 

{

if (this.lFirstLoad)  //只添加一次

{

if (this.lDefaultAssemblies) 

{

this.AddDefaultAssemblies();

}

this.AddAssembly(this.cSupportAssemblyPath + "RemoteAccess.dll","RemoteAccess");

this.AddAssembly(this.cSupportAssemblyPath + "ZZCompiler.dll","ZZCompiler");

this.lFirstLoad = false;

}

 

StringBuilder sb = new StringBuilder("");

 

//添加编译所需要的命名空间

sb.Append(this.cNamespaces);

sb.Append("\r\n");

 

if (this.cScriptingLanguage == "CSharp") 

{

// 构造一个类,实现IRemote接口

sb.Append("namespace " + this.cAssemblyNamespace + "\r\n{\r\npublic class " + this.cClassName + ":MarshalByRefObject,IRemote \r\n{\r\n");

 

// 实现Invoke方法

sb.Append(

"public object Invoke(string lcMethod,object[] parms) \r\n{\r\n" + 

"return this.GetType().InvokeMember(lcMethod,BindingFlags.InvokeMethod,null,this,parms );\r\n" +

"}\r\n\r\n" );

 

// 将代码插入到构造出来的类中

sb.Append(lcCode);

 

sb.Append("\r\n} \r\n}");  // 类结束,命名空间结束

}

else if (this.cScriptingLanguage == "VB") 

{

// 同上

sb.Append("Namespace " + this.cAssemblyNamespace + "\r\npublic class " + this.cClassName + "\r\n");

sb.Append("Inherits MarshalByRefObject\r\nImplements IRemote\r\n\r\n");

 

// 同上

sb.Append(

"Public Overridable Overloads Function Invoke(ByVal lcMethod As String, ByVal Parameters() As Object) As Object _\r\n" +

"Implements IRemote.Invoke\r\n" + 

"return me.GetType().InvokeMember(lcMethod,BindingFlags.InvokeMethod,nothing,me,Parameters)\r\n" +

"End Function\r\n\r\n" );

 

//同上

sb.Append(lcCode);

 

sb.Append("\r\n\r\nEnd Class\r\nEnd Namespace\r\n");  // 同上

}

 

if (this.lSaveSourceCode)

{

this.cSourceCode = sb.ToString();

}

 

if (!this.CompileAssembly(sb.ToString()) ) //编译生成程序集

return null;

 

object loTemp = this.CreateInstance(); //创建实例

if (loTemp == null)

return null;

}

 

return this.CallMethod(this.oObjRef,lcMethodName,loParameters);

}

        /// <summary>

        /// 执行代码块

        /// </summary>

        /// <param name="lcCode"></param>

        /// <param name="loParameters"></param>

        /// <returns></returns>

public object ExecuteSection(string lcCode, params object[] loParameters) 

{

            //构造一个方法,将代码块插入到该方法体中

if (this.cScriptingLanguage == "CSharp")

return this.ExecuteMethod("public object ExecuteCode(params object[] Parameters) \r\n{\r\n" + 

lcCode + 

"\r\n}",

"ExecuteCode",loParameters);

else if (this.cScriptingLanguage == "VB")

return this.ExecuteMethod("public function ExecuteCode(ParamArray Parameters() As Object) as object\r\n" + 

lcCode + 

"\r\nend function\r\n",

"ExecuteCode",loParameters);

 

return null;

}

   

        /// <summary>

        /// 编译源代码生成程序集

        /// </summary>

        /// <param name="lcSource"></param>

        /// <returns></returns>

public bool CompileAssembly(string lcSource) 

{

//this.oParameters.GenerateExecutable = false;

 

if (this.oAppDomain == null && this.cOutputAssembly == null) //在编译后的程序集存放在内存中,稍后直接记载到当前程序域

this.oParameters.GenerateInMemory = true;

else if (this.oAppDomain != null && this.cOutputAssembly == null) //编译后的程序集存放在disk上,稍后加载到新建的程序域

{

this.cOutputAssembly = "ZZ_" + Guid.NewGuid().ToString() + ".dll"; //编译生成后的程序及文件名

this.oParameters.OutputAssembly = this.cOutputAssembly;

}

else {

 this.oParameters.OutputAssembly = this.cOutputAssembly;

}

 

this.oCompiled = this.oCompiler.CompileAssemblyFromSource(this.oParameters,lcSource); //编译

 

if (oCompiled.Errors.HasErrors)  //编译是否出错

{

this.bError = true;

 

// 格式化出错信息,方面外部查看

this.cErrorMsg = oCompiled.Errors.Count.ToString() + " Errors:";

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

this.cErrorMsg = this.cErrorMsg  + "\r\nLine: " + oCompiled.Errors[x].Line.ToString() + " - " + 

                              oCompiled.Errors[x].ErrorText;

return false;

}

 

if (this.oAppDomain == null)

this.oAssembly = oCompiled.CompiledAssembly;

 

return true;

}

        /// <summary>

        /// 创建实例

        /// </summary>

        /// <returns></returns>

public object CreateInstance() 

{

if (this.oObjRef != null) 

{

return this.oObjRef;

}

 

try 

{

                //直接将程序集加载到当前应用域,然后创建实例

if (this.oAppDomain == null)

try 

{

this.oObjRef =  oAssembly.CreateInstance(this.cAssemblyNamespace + "." + this.cClassName);

return this.oObjRef;

}

catch(Exception ex) 

{

this.bError = true;

this.cErrorMsg = ex.Message;

return null;

}

                //将程序集加载到新建的程序域,然后创建实例

else 

{

RemoteAccess.RemoteAccess factory = (RemoteAccess.RemoteAccess)this.oAppDomain.CreateInstance( "RemoteAccess", "RemoteAccess.RemoteAccess" ).Unwrap();

 

this.oObjRef = factory.Create( this.cOutputAssembly, this.cAssemblyNamespace + "." + this.cClassName, null );

 

return this.oObjRef;

}

}

catch(Exception ex) 

{

this.bError = true;

this.cErrorMsg = ex.Message;

return null;

}

 

}

        /// <summary>

        /// 使用指定的参数,在指定的对象上调用指定方法

        /// </summary>

        /// <param name="loObject"></param>

        /// <param name="lcMethod"></param>

        /// <param name="loParameters"></param>

        /// <returns></returns>

public object CallMethod(object loObject,string lcMethod, params object[] loParameters) 

{

try 

{

                if (this.oAppDomain == null)

                    //直接通过反射

                    return loObject.GetType().InvokeMember(lcMethod, BindingFlags.InvokeMethod, null, loObject, loParameters);

                else

                {

                    // 不能使用反射

                    object loResult;

                    try

                    {

                        // 将对象转换成远程调用接口,直接调用其方法

                        IRemote loRemote = (IRemote)loObject;

                        loResult = loRemote.Invoke(lcMethod, loParameters);

                    }

                    catch (Exception ex)

                    {

                        this.bError = true;

                        this.cErrorMsg = ex.Message;

                        return null;

                    }

                    return loResult;

                }

}

catch(Exception ex) 

{

this.bError = true;

this.cErrorMsg = ex.Message;

}

return null;

}

        /// <summary>

        /// 创建新的应用程序域(如果调用该方法,程序集就会在新建的应用程序域中被加载,否则程序集就会加载到当前应用程序域[这样就不能单独卸载])

        /// </summary>

        /// <param name="lcAppDomain"></param>

        /// <returns></returns>

public bool CreateAppDomain(string lcAppDomain) 

{

if (lcAppDomain == null)

lcAppDomain = "ZZAppDomain";

 

AppDomainSetup loSetup = new AppDomainSetup();

loSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;

 

            this.oAppDomain = AppDomain.CreateDomain(lcAppDomain, null, loSetup);

return true;

}

        /// <summary>

        /// 卸载应用程序域

        /// </summary>

        /// <returns></returns>

private bool UnloadAppDomain()

{

if (this.oAppDomain != null)

  AppDomain.Unload(this.oAppDomain);

 

this.oAppDomain = null;

 

if (this.cOutputAssembly != null) 

{

try 

{

File.Delete(this.cOutputAssembly);

}

catch(Exception) {;}

}

 

return true;

}

        /// <summary>

        /// 

        /// </summary>

public void Release() 

{

this.oObjRef = null;

}

        /// <summary>

        /// 释放资源

        /// </summary>

        public void Dispose()

        {

            this.Release();

            this.UnloadAppDomain();

        }

 

~ZZCompiler() 

{

this.Dispose();

}

}

 

   

}

 

文件IRemote.cs:

using System;

using System.Reflection;

 

namespace RemoteAccess

{

    public interface IRemote

    {

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

    }

}

 

文件RemoteAccess.cs:

using System;

using System.Reflection;

 

namespace RemoteAccess

{

    public class RemoteAccess:MarshalByRefObject

    {

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

 

public RemoteAccess() {}

 

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

{

return (IRemote) Activator.CreateInstanceFrom(

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

null, null, null ).Unwrap();

}

    }

}

 

自动动手修改实例代码,即可看到神奇的程序代码执行器。

关键词:动态  编译 

收藏 推荐 打印 | 录入:blue1000 | 阅读:
本文评论   查看全部评论 (2)
表情: 姓名: 字数
点评:
       
评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事/刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款
第 2 楼
* 匿名 发表于 2016/12/25 13:22:03
http://www.blue1000.com/bkhtml/c118/2009-11/65658.htm 竞选大学学委的发言稿 http://www.135995.com/show/21236.html 竞选村长的发言稿 http://www.135995.com/show/21235.html
第 1 楼
* 匿名 发表于 2016/12/24 13:17:49
http://www.blue1000.com/bkhtml/c118/2009-11/65658.htm 我的玩具作文 http://www.135995.com/details/zs528.html 我的伙伴作文 http://www.135995.com/details/zs383.html