【问题标题】:Loading an assembly generated by the Roslyn compiler加载由 Roslyn 编译器生成的程序集
【发布时间】:2012-05-25 08:31:01
【问题描述】:

我正在使用 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)

大致翻译成

模块中应有程序集清单。

有人知道我在这里缺少什么吗?

【问题讨论】:

  • 您的代码中有几个错误。显然,您已经弄清楚了它们(但需要 PDB 不在其中)。下次看result.Diagnostics,看看是什么问题。

标签: c# assemblies roslyn


【解决方案1】:

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

代码的问题在于两件事,通过查看来自

的返回值你会发现
EmitResult result = compilation.Emit(file);

如果您查看 EmitResult 对象的属性,您会发现 results.Diagnostics 成员中有 2 个错误。

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

所以,要解决这个问题, 1.需要将输出标记为dll 2.您需要添加'using System;'到您传递给 API 的代码或说“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();

【讨论】:

    【解决方案2】:

    我一直在向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
    

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

    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 line to compile, create and execute: O2 Script to use Roslyn to Dynamically compile and execute a method

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

    【讨论】:

      【解决方案3】:

      有一个用于参考的新 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)
      );
      

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

      【讨论】:

        【解决方案4】:

        这段代码运行良好:

        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
        }
        

        【讨论】:

        • 只是一段没有解释的代码,用处不大。这是否意味着你解决了你的问题?或者这应该只是问题的延伸?
        • 请注意,在 CompilationsOptions 中,AssemblyKind 已重命名为:OutputKind.DynamicallyLinkedLibrary
        • 作为参考,原始代码的问题之一是未定义 OutputKind(因为其中一个错误是需要使用静态 Main 方法)
        【解决方案5】:

        原来我需要创建一个 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);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-13
          • 1970-01-01
          • 1970-01-01
          • 2017-07-12
          • 1970-01-01
          • 2014-06-05
          • 2013-05-16
          相关资源
          最近更新 更多