下面的示例程序编译了两个内存中的程序集。第一次编译正常。第二个失败,因为它需要访问第一个程序集中的类,并且该类型不可用。在C#中,你如何从另一个内存组件中引用类型?
具体而言:CompilerParameters类的ReferencedAssemblies成员是一个字符串集合,它用于加载程序集的清单以获取它们的类型。看来C#编译器严格从清单中获取类型,而不是通过使用反射(可能出于性能原因)。无论如何,当在内存中构造程序集时,没有文件并且没有清单,因此第二个程序集构建失败并出现错误像这样:
编译器错误:元数据文件“ax5lw0tl,版本= 0.0.0.0,文化=中立,公钥=空”找不到
添加一个AssemblyResolver事件处理程序不起作用。我试过这个,它看起来并没有被调用过。从我所能告诉的(我是一个新手,用.NET来承担我)编译器只关心清单;它实际上并未尝试在此时加载程序集,因此AssemblyResolver不在图片中。
我可以,如果不顾一切,在磁盘上构建我的程序集,这将解决直接的问题,有一个物理的dll和清单读取。我宁愿不这样做,因为它导致必须管理将成为磁盘上临时程序集的大量集合。
我很乐观.net可以做到这一点,作为新手,我只是想念它。我希望代码示例中的间距可以正常显示,它似乎可以在预览窗口中正确显示一段时间,但是一旦语法高亮显示完成,它就会重新渲染并且间距不正确,但它仍然可读。
using System;
using System.CodeDom.Compiler;
using System.Reflection;
using System.Collections.Generic;
using Microsoft.CSharp;
namespace AsmCompileTest
{
class Program
{
static Assembly Compile(string code, Assembly referencedAssembly)
{
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = false;
cp.GenerateInMemory = true;
if(null != referencedAssembly)
{
cp.ReferencedAssemblies.Add(referencedAssembly.FullName);
}
CodeDomProvider provider = new CSharpCodeProvider(new Dictionary<string,string> { { "CompilerVersion", "v3.5" } });
CompilerResults compilerResults = provider.CompileAssemblyFromSource(cp, code);
if(compilerResults.Errors.HasErrors)
{
foreach(CompilerError error in compilerResults.Errors)
{
Console.WriteLine("COMPILER ERROR: " + error.ErrorText);
}
}
return compilerResults.CompiledAssembly;
}
static string Code1 = "using System;" +
"public class HelloClass" +
" {" +
" public HelloClass() { Console.WriteLine(\"Hello, World!\"); }" +
" }";
static string Code2 = "using System;" +
"public class TestClass" +
" {" +
" public TestClass() { new HelloClass(); }" +
" }";
static void Main()
{
Assembly asm1 = Compile(Code1, null);
Console.WriteLine("Compiled: " + asm1.FullName);
asm1.GetType("HelloClass").InvokeMember(String.Empty, BindingFlags.CreateInstance, null, null, null);
Assembly asm2 = Compile(Code2, asm1);
Console.WriteLine("Compiled: " + asm2.FullName);
asm2.GetType("TestClass").InvokeMember(String.Empty, BindingFlags.CreateInstance, null, null, null);
}
}
}
.Net编译器似乎没有留下临时程序集。它可能会删除它们(请参阅TempFileCollection。) 我已经通过编译磁盘上的程序集来运行代码。我必须咬紧牙关并管理这些临时文件,但至少它可以工作。 – 2009-01-18 06:36:00