下面的示例程序編譯了兩個內存中的程序集。第一次編譯正常。第二個失敗,因爲它需要訪問第一個程序集中的類,並且該類型不可用。在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