代码之家  ›  专栏  ›  技术社区  ›  Richard Friend

在运行时编译代码,加载到当前AppDomain中,但type.getType看不到它

  •  5
  • Richard Friend  · 技术社区  · 15 年前

    我在运行时编译了一些代码,然后将程序集加载到当前的AppDomain中,但是当我尝试执行type.getType时,它找不到类型…

    下面是我如何编译代码…

    public static Assembly CompileCode(string code)
        {
            Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
            ICodeCompiler compiler = provider.CreateCompiler();
            CompilerParameters compilerparams = new CompilerParameters();
            compilerparams.GenerateExecutable = false;
            compilerparams.GenerateInMemory = false;
    
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                try
                {
                    string location = assembly.Location;
                    if (!String.IsNullOrEmpty(location))
                    {
                        compilerparams.ReferencedAssemblies.Add(location);
                    }
                }
                catch (NotSupportedException)
                {
                    // this happens for dynamic assemblies, so just ignore it. 
                }
            } 
            CompilerResults results =
               compiler.CompileAssemblyFromSource(compilerparams, code);
            if (results.Errors.HasErrors)
            {
                StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
                foreach (CompilerError error in results.Errors)
                {
                    errors.AppendFormat("Line {0},{1}\t: {2}\n",
                           error.Line, error.Column, error.ErrorText);
                }
                throw new Exception(errors.ToString());
            }
            else
            {
                AppDomain.CurrentDomain.Load(results.CompiledAssembly.GetName());
                return results.CompiledAssembly;
            }
        }
    

    从编译的程序集中获取类型后,此位失败。很好,似乎无法使用type.gettype找到它。

    Assembly assem = RuntimeCodeCompiler.CompileCode(code);
    string typeName = 
          String.Format("Peverel.AppFramework.Web.GenCode.ObjectDataSourceProxy_{0}",
            safeTypeName);
    
    
    
    Type t = assem.GetType(typeName); //This works just fine..
    Type doesntWork = Type.GetType(t.AssemblyQualifiedName);
    Type doesntWork2 = Type.GetType(t.Name);
    
    
    
    ....
    
    2 回复  |  直到 15 年前
        1
  •  8
  •   Richard Friend    15 年前

    发现 this 一段很好的代码,可以确保无论如何加载程序集,它始终可以从type.gettype获得。

    我的类用于将代码编译到当前AppDomain中,现在看起来如下:

    public static class RuntimeCodeCompiler
    {
        private static volatile Dictionary<string, Assembly> cache = new Dictionary<string, Assembly>();
        private static object syncRoot = new object();
        static Dictionary<string, Assembly> assemblies = new Dictionary<string, Assembly>();
        static RuntimeCodeCompiler()
        {
            AppDomain.CurrentDomain.AssemblyLoad += (sender, e) =>
            {
                assemblies[e.LoadedAssembly.FullName] = e.LoadedAssembly;
            };
            AppDomain.CurrentDomain.AssemblyResolve += (sender, e) =>
            {
                Assembly assembly = null;
                assemblies.TryGetValue(e.Name, out assembly);
                return assembly;
            };
    
        }
    
    
        public static Assembly CompileCode(string code)
        {
    
            Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
            ICodeCompiler compiler = provider.CreateCompiler();
            CompilerParameters compilerparams = new CompilerParameters();
            compilerparams.GenerateExecutable = false;
            compilerparams.GenerateInMemory = false;
    
    
    
            foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                try
                {
                    string location = assembly.Location;
                    if (!String.IsNullOrEmpty(location))
                    {
                        compilerparams.ReferencedAssemblies.Add(location);
                    }
                }
                catch (NotSupportedException)
                {
                    // this happens for dynamic assemblies, so just ignore it. 
                }
            } 
    
    
            CompilerResults results =
               compiler.CompileAssemblyFromSource(compilerparams, code);
            if (results.Errors.HasErrors)
            {
                StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
                foreach (CompilerError error in results.Errors)
                {
                    errors.AppendFormat("Line {0},{1}\t: {2}\n",
                           error.Line, error.Column, error.ErrorText);
                }
                throw new Exception(errors.ToString());
            }
            else
            {
    
                AppDomain.CurrentDomain.Load(results.CompiledAssembly.GetName());
                return results.CompiledAssembly;
            }
    
        }
    
        public static Assembly CompileCodeOrGetFromCache(string code,  string key)
        {
            bool exists = cache.ContainsKey(key);
    
            if (!exists)
            {
    
                lock (syncRoot)
                {
                    exists = cache.ContainsKey(key);
    
                    if (!exists)
                    {
                        cache.Add(key, CompileCode(code));
                    }
                }
            }
    
            return cache[key];
        }
    
    
    }
    
        2
  •  -1
  •   Achim    15 年前

    您应该多读一些关于程序集加载、类型解析…我完全不知道您的代码为什么工作,但我想您有以下问题:

    编译程序集,然后调用appdomain.currentdomain.load加载程序集。但不返回刚加载的程序集。从编译结果返回程序集。现在,您有了同一程序集的两个实例,并且该程序集的每种类型都有两次。这些对具有相同的名称,但它们不是相同的类型!