簡體   English   中英

使用Roslyn單獨編譯類並在程序集中將它們組合在一起

[英]Compiling Classes separately using Roslyn and combining them together in an assembly

我有一組不相交的動態編寫的類,我想單獨編譯(並修復編譯錯誤)。 然后我想把它們組合成同一個組件。 由於它們已經編譯過,我不想簡單地將它們的語法樹傳遞給匯編編譯(為了避免編譯兩次)。 我試圖將它們編譯成netmodules,然后使用這些netmodules作為程序集的引用,但生成的程序集沒有所需的類型。

這是我的測試代碼(非常類似於Roslyn的CompilationEmitTests.MultipleNetmodulesWithPrivateImplementationDetails())

public static class Program
{

    public static void Main()
    {
        var s1 = @"public class A {internal object o1 = new { hello = 1, world = 2 }; public static string M1() {    return ""Hello, "";}}";
        var s2 = @"public class B : A{internal object o2 = new { hello = 1, world = 2 };public static string M2(){    return ""world!"";}}";
        var s3 = @"public class Program{public static void Main(){    System.Console.Write(A.M1());    System.Console.WriteLine(B.M2());}}";
        var comp1 = CreateCompilationWithMscorlib("a1", s1, compilerOptions: TestOptions.ReleaseModule);
        var ref1 = comp1.EmitToImageReference();

        var comp2 = CreateCompilationWithMscorlib("a2", s2, compilerOptions: TestOptions.ReleaseModule, references: new[] { ref1 });
        var ref2 = comp2.EmitToImageReference();

        var comp3 = CreateCompilationWithMscorlib("a3", s3, compilerOptions: TestOptions.ReleaseExe.WithModuleName("C"), references: new[] { ref1, ref2 });

        var ref3 = comp3.EmitToImageReference();

        IEnumerable<byte> result = comp3.EmitToArray();

        Assembly assembly = Assembly.Load(result.ToArray());

        Module module = assembly.GetModule("C");

        Type prog = module.GetType("Program");

        object instance = Activator.CreateInstance(prog);

        MethodInfo method = prog.GetMethod("Main");

        method.Invoke(null, null);
    }

    public static ImmutableArray<byte> ToImmutable(this MemoryStream stream)
    {
        return ImmutableArray.Create<byte>(stream.ToArray());
    }

    internal static ImmutableArray<byte> EmitToArray
    (
        this Compilation compilation,
        EmitOptions options = null,
        Stream pdbStream = null
    )
    {
        var stream = new MemoryStream();

        if (pdbStream == null && compilation.Options.OptimizationLevel == OptimizationLevel.Debug)
        {
            pdbStream = new MemoryStream();
        }

        var emitResult = compilation.Emit(
            peStream: stream,
            pdbStream: pdbStream,
            xmlDocumentationStream: null,
            win32Resources: null,
            manifestResources: null,
            options: options);

        return stream.ToImmutable();
    }
    public static MetadataReference EmitToImageReference(
        this Compilation comp
    )
    {
        var image = comp.EmitToArray();
        if (comp.Options.OutputKind == OutputKind.NetModule)
        {
            return ModuleMetadata.CreateFromImage(image).GetReference(display: comp.AssemblyName);
        }
        else
        {
            return AssemblyMetadata.CreateFromImage(image).GetReference(display: comp.AssemblyName);
        }
    }

    private static CSharpCompilation CreateCompilationWithMscorlib(string assemblyName, string code, CSharpCompilationOptions compilerOptions = null, IEnumerable<MetadataReference> references = null)
    {
        SourceText sourceText = SourceText.From(code, Encoding.UTF8);
        SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(sourceText, null, "");

        MetadataReference mscoreLibReference = AssemblyMetadata.CreateFromFile(typeof(string).Assembly.Location).GetReference();

        IEnumerable<MetadataReference> allReferences = new MetadataReference[] { mscoreLibReference };

        if (references != null)
        {
            allReferences = allReferences.Concat(references);
        }

        CSharpCompilation compilation = CSharpCompilation.Create
        (
            assemblyName,
            new[] {syntaxTree},
            options : compilerOptions,
            references: allReferences
        );

        return compilation;
    }

}

Main()在靜態方法Invoke()處拋出異常,因為它找不到對A和B類的引用。

我究竟做錯了什么?

以下是用戶0xd4d在Github上針對同一問題發布的答案。 我測試它是否有效:

在需要訪問netmodule之前,必須調用LoadModule

assembly.LoadModule("a1.netmodule", a1_netmodule_bytes);
assembly.LoadModule("a2.netmodule", a2_netmodule_bytes);

如果您已將它們全部保存到磁盤,則無需執行此操作。

我仍然不明白他的意思是說如果我把它保存到磁盤我不需要這樣做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM