阿赛·游梦鱼·郭言赛·阿赛工作室
全站技术源码素材

与动态执行的C#代码进行通讯

  • 发布时间:2011年7月27日 最近更新:5-2 发布:biancheng 编辑:eesai 字体:
  • 1、简介

    能够动态执行 C# 代码是一件很酷的功能,比如,我们可以在控制台中输入一行 C# 代码,然后程序 自动编译并执行这一行代码,将结果显示给我们。这差不多就是一个最简单的 C# 代码解释器了。

    动态执行 C# 代码又是一件很有用的功能,比如,我们可以将某些代码写在某个文件之中,由程序集 在执行时进行加载,改变这些代码不用中止程序,当程序再次加载这些代码时,就自动执行的是新代码了 。

    下面,我将在写一个简单C# 代码解释器,然后将在 C# 代码解释器之中加入动态代码与解释器环境间 的动态交互机制,来演示一个很好很强大的应用。

    2、简单的 C# 代码解释器

    关于如何动态执行 C# 代码在 Jailu.Net 的《如何用C#动态编译、执行代码》一文中讲述的很清晰。 采用该文所述方式写一个 C# 代码解释器:

    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Globalization;
    using Microsoft.CSharp;
    using System.CodeDom;
    using System.CodeDom.Compiler;
    using System.Text;
    using System.IO;
    using System.Xml;
    namespace Test
    {
       class Program
       {
         static void Main(string[] args)
         {
           Console.Write(">> ");
           String cmd;
           Context cxt = new Context();
           while ((cmd = Console.ReadLine().Trim()) != "exit")
           {
             if (!String.IsNullOrEmpty(cmd))
             {
               Console.WriteLine();
               cxt.Invoke(cmd);
             }
             Console.Write("\n>> ");
           }
         }
       }
       public class Context
       {
         public CSharpCodeProvider CodeProvider { get; set; }
         public IDictionary Assemblys { get; set; }
         public Context()
         {
           CodeProvider = new CSharpCodeProvider(new Dictionary() { { "CompilerVersion", "v3.5" } });
           Assemblys = new Dictionary();
           Assembly[] al = AppDomain.CurrentDomain.GetAssemblies();
           foreach (Assembly a in al)
           {
             AddAssembly(a);
           }
           AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler (CurrentDomain_AssemblyLoad);
         }
         private void AddAssembly(Assembly a)
         {
           if (a != null)
           {
             Assemblys.Add(a.FullName, a);
           }
         }
         void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
         {
           Assembly a = args.LoadedAssembly;
           if (!Assemblys.ContainsKey(a.FullName))
           {
             AddAssembly(a);
           }
         }
         public CompilerParameters CreateCompilerParameters()
         {
           CompilerParameters cp = new CompilerParameters();
           cp.GenerateExecutable = false;
           cp.GenerateInMemory = true;
           if (Assemblys != null)
           {
             foreach (Assembly a in Assemblys.Values)
             {
               cp.ReferencedAssemblies.Add(a.Location);
             }
           }
           return cp;
         }
         public void Invoke(String cmd)
         {
           String inputCmdString = cmd.Trim();
           if (String.IsNullOrEmpty(inputCmdString)) return;
           String fullCmd = BuildFullCmd(inputCmdString);
           CompilerResults cr = CodeProvider.CompileAssemblyFromSource (CreateCompilerParameters(), fullCmd);
           if (cr.Errors.HasErrors)
           {
             Boolean recompileSwitch = true;
             foreach (CompilerError err in cr.Errors)
             {
               //CS0201 : Only assignment, call, increment, decrement, and new object expressions can be
               //used as a statement
               if (!err.ErrorNumber.Equals("CS0201"))
               {
                 recompileSwitch = false;
                 break;
               }
             }
             // 重新编译
             if (recompileSwitch)
             {
               String dynaName = "TempArg_Dynamic_" + DateTime.Now.Ticks.ToString ();
               inputCmdString = String.Format(" var {0} = ", dynaName) + inputCmdString;
               inputCmdString += ";\n System.Console.WriteLine(" + dynaName + ");";
               fullCmd = BuildFullCmd(inputCmdString);
               cr = CodeProvider.CompileAssemblyFromSource(CreateCompilerParameters (), fullCmd);
             }
             if (cr.Errors.HasErrors)
             {
               Console.WriteLine("编译错误:");
               foreach (CompilerError err in cr.Errors)
               {
                 Console.WriteLine(err.ErrorNumber);
                 Console.WriteLine(err.ErrorText);
               }
               return;
             }
           }
           Assembly assem = cr.CompiledAssembly;
           Object dynamicObject = assem.CreateInstance("Test.DynamicClass");
           Type t = assem.GetType("Test.DynamicClass");
           MethodInfo minfo = t.GetMethod("MethodInstance");
           minfo.Invoke(dynamicObject, null);
         }
         private String BuildFullCmd(String inputCmdString)
         {
           String fullCmd = String.Empty;
           fullCmd += @"
             namespace Test
             {
               public class DynamicClass
               {
                 public void MethodInstance()
                 {
                   " + inputCmdString + @";
                 }
               }
             }";
           return fullCmd;
         }
       }
    }


    MapSiteMapRssGoTop