Loading an assembly generated by the Roslyn compiler

后端 未结 5 592
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-31 17:54

I\'m generating a Greeter.dll using the Roslyn compiler. My problem occurs trying to load the DLL file.

Here\'s the code:

using System;

using Rosly         


        
相关标签:
5条回答
  • 2020-12-31 18:13

    I have been adding Roslyn support to the O2 Plarform and here is how you can use its Roslyn support to compile (code), create (and assembly) and invoke (its method) one line of code:

    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
    

    Here is a version that executes a code snippet that looks like yours (I added a return value):

    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
    

    For a couple more details and screenshots of what this looks like, see this blog post: 1 line to compile, create and execute: O2 Script to use Roslyn to Dynamically compile and execute a method

    UPDATE: see http://blog.diniscruz.com/search/label/Roslyn for a large number number of Roslyn related posts and tools (created using the O2 Platform)

    0 讨论(0)
  • 2020-12-31 18:15

    This code worked beautifully:

    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
    }
    
    0 讨论(0)
  • 2020-12-31 18:22

    Turns out I needed to create a pdb file.

    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);
    }
    
    0 讨论(0)
  • 2020-12-31 18:24

    I stumbled across this and, even though you have an accepted answer, I don't think it's helpful in general. So, I'll just leave this here for future searchers like myself.

    The problem with the code is two things, which you would have found out by looking at the returned value from

    EmitResult result = compilation.Emit(file);
    

    If you look at the properties on the EmitResult object, you would have found that there were 2 errors in the results.Diagnostics member.

    1. Main method not found
    2. Couldn't find class Console

    So, to fix the problem, 1. You need to mark the output as a dll 2. You need to add 'using System;' to the code you're passing into the API or say 'System.Console.WriteLine'

    The following code works making changes to fix those two issues:

            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();
    
    0 讨论(0)
  • 2020-12-31 18:24

    There is a new API for the References that looks like this:

    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)
    );
    

    This is with the latest Roslyn-CTP 2012 in Sept...

    0 讨论(0)
提交回复
热议问题