加载由 Roslyn 编译器生成的程序集

本文关键字:程序集 编译器 Roslyn 加载 | 更新日期: 2023-09-27 18:35:14

我正在使用Roslyn编译器生成一个Greeter.dll。尝试加载 DLL 文件时出现问题。

代码如下:

using System;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using System.IO;
using System.Reflection;
using System.Linq;
namespace LoadingAClass
{
    class Program
    {
        static void Main(string[] args)
        {
            var syntaxTree = SyntaxTree.ParseCompilationUnit(@"
class Greeter
{
    static void Greet()
    {
        Console.WriteLine(""Hello, World"");
    }
}");
            var compilation = Compilation.Create("Greeter.dll",
                syntaxTrees: new[] { syntaxTree },
                references: new[] {
                    new AssemblyFileReference(typeof(object).Assembly.Location),
                    new AssemblyFileReference(typeof(Enumerable).Assembly.Location),
                });
            Assembly assembly;
            using (var file = new FileStream("Greeter.dll", FileMode.Create))
            {
                EmitResult result = compilation.Emit(file);
            }
            assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), @"Greeter.dll"));
            Type type = assembly.GetType("Greeter");
            var obj = Activator.CreateInstance(type);
            type.InvokeMember("Greet",
                BindingFlags.Default | BindingFlags.InvokeMethod,
                null,
                obj,
                null);
            Console.WriteLine("<ENTER> to continue");
            Console.ReadLine();
        }
    }
    // Thanks, http://blogs.msdn.com/b/csharpfaq/archive/2011/11/23/using-the-roslyn-symbol-api.aspx
}

错误消息出现在行assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), @"Greeter.dll"));上,并读取

Im Modul wurde ein Assemblymanifest erwartet.(Ausnahme von HRESULT: 0x80131018)

大致翻译为

模块中应包含程序集清单。

有谁知道我在这里错过了什么?

加载由 Roslyn 编译器生成的程序集

我偶然发现了这个,即使你有一个公认的答案,我认为它总体上没有帮助。 所以,我就把这个留给像我这样的未来搜索者。

代码的问题有两件事,您可以通过查看返回的值来发现

EmitResult result = compilation.Emit(file);

如果查看 EmitResult 对象上的属性,您会发现结果中有 2 个错误。诊断成员。

  1. 未找到主方法
  2. 找不到类控制台

因此,要解决问题,1.您需要将输出标记为dll2. 您需要在传递到 API 的代码中添加"using System;"或说"System.Console.WriteLine"

以下代码用于进行更改以解决这两个问题:

        var outputFile = "Greeter.dll";
        var syntaxTree = SyntaxTree.ParseCompilationUnit(@"
 // ADDED THE FOLLOWING LINE
using System;
class Greeter
{
    public void Greet()
    {
        Console.WriteLine(""Hello, World"");
    }
}");
        var compilation = Compilation.Create(outputFile,
            syntaxTrees: new[] { syntaxTree },
            references: new[] {
                new AssemblyFileReference(typeof(object).Assembly.Location),
                new AssemblyFileReference(typeof(Enumerable).Assembly.Location),
            },
// ADDED THE FOLLOWING LINE
            options: new CompilationOptions(OutputKind.DynamicallyLinkedLibrary));
        using (var file = new FileStream(outputFile, FileMode.Create))
        {
            EmitResult result = compilation.Emit(file);
        }
        Assembly assembly = Assembly.LoadFrom("Greeter.dll");
        Type type = assembly.GetType("Greeter");
        var obj = Activator.CreateInstance(type);
        type.InvokeMember("Greet",
            BindingFlags.Default | BindingFlags.InvokeMethod,
            null,
            obj,
            null);
        Console.WriteLine("<ENTER> to continue");
        Console.ReadLine();

我一直在向O2 Plarform添加Roslyn支持,以下是如何使用其Roslyn支持来编译(代码),创建(和汇编)和调用(其方法)一行代码:

return @"using System; class Greeter { static string Greet() {  return ""Another hello!!""; }}"
        .tree().compiler("Great").create_Assembly().type("Greeter").invokeStatic("Greet"); 
//O2Ref:O2_FluentSharp_Roslyn.dll

这是一个执行看起来像你的代码片段的版本(我添加了一个返回值):

panel.clear().add_ConsoleOut();
var code = @"
using System;
class Greeter
{
    static string Greet()
    { 
        Console.WriteLine(""Hello, World""); 
        return ""hello from here"";
    }
}";
var tree = code.astTree();
if (tree.hasErrors())
    return tree.errors();   
var compiler = tree.compiler("Great")
                   .add_Reference("mscorlib");
if (compiler.hasErrors()) 
    return compiler.errors();    
var assembly  =tree.compiler("Great")
                   .create_Assembly();
return assembly.type("Greeter")
               .invokeStatic("Greet"); 
//O2Ref:O2_FluentSharp_Roslyn.dll
//O2File:_Extra_methods_Roslyn_API.cs
//O2File:API_ConsoleOut.cs

有关更多详细信息和屏幕截图,请参阅此博客文章: 1 行编译、创建和执行:使用 Roslyn 动态编译和执行方法的 O2 脚本

更新:请参阅 http://blog.diniscruz.com/search/label/Roslyn 以获取大量与Roslyn相关的帖子和工具(使用O2平台创建)

引用有一个新的 API,如下所示:

var compilation = Compilation.Create(outputFile,
    syntaxTrees: new[] { syntaxTree },
    references: new[] {
        new MetadataFileReference(typeof(object).Assembly.Location),
        new MetadataFileReference(typeof(Enumerable).Assembly.Location),
    },
    options: new CompilationOptions(OutputKind.DynamicallyLinkedLibrary)
);

这是最新的Roslyn-CTP 2012在9月...

这段代码运行得很好:

using System;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using System.IO;
using System.Reflection;
using System.Linq;
namespace LoadingAClass
{
    class Program
    {
        static void Main(string[] args)
        {
            var syntaxTree = SyntaxTree.ParseCompilationUnit(@"
using System;
namespace HelloWorld
{
    class Greeter
    {
        public static void Greet()
        {
            Console.WriteLine(""Hello, World"");
        }
    }
}");
            string dllPath = Path.Combine(Directory.GetCurrentDirectory(), "Greeter.dll");
            string pdbPath = Path.Combine(Directory.GetCurrentDirectory(), "Greeter.pdb");
            var compilation = Compilation.Create(dllPath,
                new CompilationOptions(
                    assemblyKind: AssemblyKind.DynamicallyLinkedLibrary
                ))
                .AddSyntaxTrees( syntaxTree )
                .AddReferences(new AssemblyFileReference(typeof(object).Assembly.Location))
                .AddReferences(new AssemblyFileReference(typeof(Enumerable).Assembly.Location));
            EmitResult result;
            using (FileStream dllStream = new FileStream(dllPath, FileMode.OpenOrCreate))
            using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate))
            {
                result = compilation.Emit(
                    executableStream: dllStream,
                    pdbFileName: pdbPath,
                    pdbStream: pdbStream);
            }
            if (result.Success)
            {
                //assembly = Assembly.LoadFile(Path.Combine(Directory.GetCurrentDirectory(), @"Greeter.dll"));
                Assembly assembly = Assembly.LoadFrom(@"Greeter.dll");
                Type type = assembly.GetType("HelloWorld.Greeter");
                var obj = Activator.CreateInstance(type);
                type.InvokeMember("Greet",
                    BindingFlags.Default | BindingFlags.InvokeMethod,
                    null,
                    obj,
                    null);
            }
            else
            {
                Console.WriteLine("No Go");
                Console.WriteLine(result.Diagnostics.ToString());
            }
            Console.WriteLine("<ENTER> to continue");
            Console.ReadLine();
        }
    }
    // Thanks, http://blogs.msdn.com/b/csharpfaq/archive/2011/11/23/using-the-roslyn-symbol-api.aspx
    // Thanks, http://social.msdn.microsoft.com/Forums/en-US/roslyn/thread/d620a4a1-3a90-401b-b946-bfa1fc6ad7a2
}

原来我需要创建一个 pdb 文件。

using (FileStream dllStream = new FileStream(dllPath, FileMode.OpenOrCreate))
using (FileStream pdbStream = new FileStream(pdbPath, FileMode.OpenOrCreate))
{
    result = compilation.Emit(
       executableStream: dllStream,
       pdbFileName: pdbPath,
       pdbStream: pdbStream);
}