直接贴代码了:
using Microsoft.CSharp; using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Reflection; using System.Text; namespace DynamicCompiler { class Program { static void Main(string[] args) { //1.CSharpCodePrivoder CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider(); //2.ICodeComplier ICodeCompiler objICodeCompiler = objCSharpCodePrivoder.CreateCompiler(); //3.CompilerParameters CompilerParameters objCompilerParameters = new CompilerParameters(); objCompilerParameters.ReferencedAssemblies.Add("System.dll"); objCompilerParameters.GenerateExecutable = false; objCompilerParameters.GenerateInMemory = true; //4.CompilerResults CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, GenerateCode()); if (cr.Errors.HasErrors) { Console.WriteLine("编译错误"); foreach (CompilerError err in cr.Errors) { Console.WriteLine(err.ErrorText); } } else { //通过反射,调用HelloWorld的实例 Assembly objAssembly = cr.CompiledAssembly; object objHelloWorld = objAssembly.CreateInstance( "DynamicCompiler.Program"); MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut"); Console.WriteLine(objMI.Invoke(objHelloWorld, null)); MethodInfo objTest = objHelloWorld.GetType().GetMethod("TestFunction"); Console.WriteLine(objTest.Invoke(objHelloWorld, null)); } Console.ReadLine(); } static string GenerateCode() { StringBuilder sb = new StringBuilder(); sb.Append("using System;"); sb.Append(Environment.NewLine); sb.Append("namespace DynamicCompiler"); sb.Append(Environment.NewLine); sb.Append("{"); sb.Append(Environment.NewLine); sb.Append(" public class Program"); sb.Append(Environment.NewLine); sb.Append(" {"); //方法1 sb.Append(Environment.NewLine); sb.Append(" public string OutPut()"); sb.Append(Environment.NewLine); sb.Append(" {"); sb.Append(Environment.NewLine); sb.Append(" return \"Hello world!\";"); sb.Append(Environment.NewLine); sb.Append(" }"); //方法2 sb.Append(Environment.NewLine); sb.Append(" public void TestFunction()"); sb.Append(Environment.NewLine); sb.Append(" {"); sb.Append(Environment.NewLine); sb.Append(" Console.WriteLine(\"我是改变的测试方法\");Console.ReadKey(); "); sb.Append(Environment.NewLine); sb.Append(" }"); sb.Append(Environment.NewLine); sb.Append(" }"); sb.Append(Environment.NewLine); sb.Append("}"); string code = sb.ToString(); Console.WriteLine(code); Console.WriteLine(); return code; } static void TestFunction() { Console.WriteLine("我是原有测试方法"); Console.ReadKey(); } } }
问题:
1.动态编译的时候,我在相同的命名空间和类名下定义了签名完全一样的函数,为什么不会报错?
2.执行的时候,打印出来的是“我是改变的测试方法”,那原有的那个函数呢?
有清楚地大侠么?求指导。
1.为什么要报错?难道说两个程序集中的class(就算namespace也一样)就不能够重名了?
2.你动态编译后在你else中是拿的编译的程序级去反射执行指定方法,和上面回答一样,都指明了是两个不同程序级,当然不会输出你当前程序级的方法的东西了。
谢谢你的回答。我只是不明白,为什么他们会编译到两个assembly里,而不是在同一个assembly里。能再解释下吗?谢谢~
@梦回大唐吟诗篇: 这几天比较忙,没来看回复,不好意思。
程序集一旦被加载就不会被卸载(不同appdomain下另当别论),这个是框架本身所决定,假设你可以对你当前程序集做修改,那么就需要在运行时感知这点并对老的程序集做卸载,但这和运行时本身是抵触的,各种type的信息及静态对象都将阻止这种事情的发生(也不应该发生),所以你写的代码实际上是生成了一个新的程序集,只是放在内存里而已。
你可以看下Assembly的几个静态方法,同样也会发现只有load这些,而没有unload。