我在运行时编译一些代码,然后将程序集加载到当前的应用程序域中,但是当我尝试执行 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);
....
发现this一段不错的代码,可以确保无论您如何加载程序集,它始终可以从 Type.GetType 获得。
我的用于将代码编译到当前应用程序域的类现在看起来像:
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];
}
}
您应该阅读更多有关程序集加载、类型解析等内容,...我根本不知道您的代码为何有效,但我猜您遇到以下问题:
编译程序集,然后调用 AppDomain.CurrentDomain.Load 加载程序集。但您不会返回刚刚加载的程序集。您从编译结果中返回程序集。现在,您有同一程序集的两个实例,并且该程序集中的每种类型都有两次。这些对具有相同的名称,但它们不是相同的类型!