动态执行 VB.NET 和 C# 代码

来源:互联网 发布:足彩数据app 编辑:程序博客网 时间:2024/05/16 15:24

有时候我们需要尝试动态地与一些代码进行交互,而不是只能执行程序内已编死的代码,那该怎么办呢?
我首先推荐各种脚本语言,如Javascript、Lua、Python等等,这些脚本语言有很多优秀的第三方类库,可以很方便的与 .NET 系统集成,让我们的程序中执行动态代码。

但如果你一定想用VB.NET或者C#的代码来运行一段程序,这里就要用到动态编译的功能了。

下面是我写的两个实例,你只需要在窗体 FormMain 中添加一个 button 和一个 textbox 即可,默认名为 Button1TextBox1

VB.NET代码

Imports System.CodeDom.CompilerImports System.ReflectionPublic Class FormMain    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click        ' 编译参数        Dim cpars As New CompilerParameters        ' 编译参数,如 /optimize /removeintchecks 等        cpars.CompilerOptions = "/optimize "        cpars.GenerateInMemory = True '在内存中编译而不输出文件        cpars.GenerateExecutable = False '并不输出执行文件        cpars.IncludeDebugInformation = False '不需要调试信息        ' 导入类库(根据自己代码的需要导入)        cpars.ReferencedAssemblies.Add("mscorlib.dll")        cpars.ReferencedAssemblies.Add("System.dll")        cpars.ReferencedAssemblies.Add("System.Data.dll")        cpars.ReferencedAssemblies.Add("System.Deployment.dll")        cpars.ReferencedAssemblies.Add("System.Drawing.dll")        cpars.ReferencedAssemblies.Add("System.Windows.Forms.dll")        cpars.ReferencedAssemblies.Add("System.Xml.dll")        cpars.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll")        ' 编译参数,为导入的类库设置全局引用(否则必须使用完整的命名空间名称才能正确调用函数)        cpars.CompilerOptions &= " /imports:" & _         "Microsoft.VisualBasic," & _         "System," & _         "System.Collections," & _         "System.Collections.Generic," & _         "System.Drawing," & _         "System.Windows.Forms"        ' 设置编译器        Dim vbc As New VBCodeProvider        'Dim vbc = CodeDomProvider.CreateProvider("VisualBasic") '等效方法        ' 一个简单的模板类        Dim codex As String = _         "Public Class CompClass" & vbCrLf & _         "    Shared Function RunCode() As Object" & vbCrLf & _         "        '$" & vbCrLf & _         "    End Function" & vbCrLf & _         "End Class"        ' 替换代码到模板类中        Dim code As String = codex.Replace("'$", TextBox1.Text)        ' 编译并返回        Dim resut As CompilerResults = vbc.CompileAssemblyFromSource(cpars, code)        ' 如果发生了错误        If resut.Errors.Count > 0 Then            MsgBox(resut.Errors(0).ToString)            Return        End If        ' 尝试调用代码        Dim asm As Assembly = resut.CompiledAssembly '获取程序集        ' 获取我们编写的静态方法        Dim mi As MethodInfo = asm.GetType("CompClass").GetMethod("RunCode")        ' 执行代码,并获取返回值        Dim ret As Object = mi.Invoke(Nothing, Nothing)        ' 对返回值进行处理        If ret IsNot Nothing Then            MsgBox(ret.ToString)        End If    End SubEnd Class

执行程序,在 Textbox1 里写入一些VB代码,按 Button1 即可立即执行里面的代码。
如果拥有返回值,程序还可以获取代码的返回值,但有可能需要你进行拆箱处理。

C#代码

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;using System.Reflection;using System.CodeDom.Compiler;namespace WindowsFormsApplication1{    public partial class FormMain : Form    {        public FormMain()        {            InitializeComponent();        }        private void Button1_Click(object sender, EventArgs e)        {            // 编译参数            var cpars = new CompilerParameters();            cpars.CompilerOptions = "/optimize ";            cpars.GenerateInMemory = true;            cpars.GenerateExecutable = false;            cpars.IncludeDebugInformation = false;            // 导入类库(根据自己代码的需要导入)            cpars.ReferencedAssemblies.Add("mscorlib.dll");            cpars.ReferencedAssemblies.Add("System.dll");            cpars.ReferencedAssemblies.Add("System.Data.dll");            cpars.ReferencedAssemblies.Add("System.Deployment.dll");            cpars.ReferencedAssemblies.Add("System.Drawing.dll");            cpars.ReferencedAssemblies.Add("System.Windows.Forms.dll");            cpars.ReferencedAssemblies.Add("System.Xml.dll");            // 编译器实例            var csc = new Microsoft.CSharp.CSharpCodeProvider();            //var csc = CodeDomProvider.CreateProvider("CSharp");            // 一个简单的模板类            // 因为C#的编译器无法设置全局命名空间,所以需要在代码中导入命名空间            var codex = @"using System;using System.Collections;using System.Collections.Generic;using System.Text;using System.Drawing;using System.Windows.Forms;class CompClass{    static public object RunCode(){        //$        return null;    }}";            // 替换代码到模板类中            var code = codex.Replace("//$", TextBox1.Text);            // 编译并返回            var resut = csc.CompileAssemblyFromSource(cpars, code);            // 错误警告            if (resut.Errors.Count > 0) {                MessageBox.Show(resut.Errors[0].ToString());                return;            }            // 调用代码            var asm = resut.CompiledAssembly;            var mi = asm.GetType("CompClass").GetMethod("RunCode");            object ret = mi.Invoke(null, null);            if (ret != null) {                MessageBox.Show(ret.ToString());            }        }    }}

C#的代码流程与VB的基本相同,区别在于C#的编译器没有导入全局命名空间的参数,因此需要在模板类里写入你需要导入的命名空间。
其他的用法基本都一样。

PS: 我有空再写一点与第三方脚本库进行交互的代码示例。