繁体   English   中英

在.Net Core 1.0中运行时编译和运行代码

[英]Compiling and Running code at runtime in .Net Core 1.0

是否可以在新的.Net Core(更好的.Net标准平台)中运行时编译和运行C#代码? 我看过一些例子(.Net Framework),但是他们使用了与netcoreapp1.0不兼容的NuGet包(.NETCoreApp,Version = v1.0)

选项#1 :使用完整的C#编译器编译程序集,加载它然后从中执行一个方法。

这需要以下包作为project.json中的依赖项:

"Microsoft.CodeAnalysis.CSharp": "1.3.0-beta1-20160429-01",
"System.Runtime.Loader": "4.0.0-rc2-24027",

然后你可以使用这样的代码:

var compilation = CSharpCompilation.Create("a")
    .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
    .AddReferences(
        MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location))
    .AddSyntaxTrees(CSharpSyntaxTree.ParseText(
        @"
using System;

public static class C
{
    public static void M()
    {
        Console.WriteLine(""Hello Roslyn."");
    }
}"));

var fileName = "a.dll";

compilation.Emit(fileName);

var a = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.GetFullPath(fileName));

a.GetType("C").GetMethod("M").Invoke(null, null);

选项#2 :使用Roslyn Scripting。 这将导致更简单的代码,但目前需要更多设置:

  • 创建NuGet.config以从Roslyn nightly feed获取包:

     <?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <add key="Roslyn Nightly" value="https://www.myget.org/F/roslyn-nightly/api/v3/index.json" /> </packageSources> </configuration> 
  • 将以下包作为依赖项添加到project.json(请注意,这是今天的包,将来需要不同的版本):

     "Microsoft.CodeAnalysis.CSharp.Scripting": "1.3.0-beta1-20160530-01", 

    您还需要导入dotnet (过时的“Target Framework Moniker”, 但仍然由Roslyn使用 ):

     "frameworks": { "netcoreapp1.0": { "imports": "dotnet5.6" } } 
  • 现在你终于可以使用Scripting了:

     CSharpScript.EvaluateAsync(@"using System;Console.WriteLine(""Hello Roslyn."");").Wait(); 

只需添加@svick选项一个答案。 如果要将程序集保留在内存中(而不是写入文件),可以使用以下方法:

AssemblyLoadContext context = AssemblyLoadContext.Default;
Assembly assembly = context.LoadFromStream(ms);

这与Net451的不同之处在于代码为:

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

我的代码同时针对Net451和Netstandard,所以我不得不使用指令来解决这个问题。 完整的代码示例如下:

                   string code = CreateFunctionCode();
                    var syntaxTree = CSharpSyntaxTree.ParseText(code);

                    MetadataReference[] references = new MetadataReference[]
                    {
                        MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
                        MetadataReference.CreateFromFile(typeof(Hashtable).GetTypeInfo().Assembly.Location)
                    }; 

                     var compilation = CSharpCompilation.Create("Function.dll",
                        syntaxTrees: new[] { syntaxTree },
                        references: references,
                        options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

                    StringBuilder message = new StringBuilder();

                    using (var ms = new MemoryStream())
                    {
                        EmitResult result = compilation.Emit(ms);

                        if (!result.Success)
                        {
                            IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
                                diagnostic.IsWarningAsError ||
                                diagnostic.Severity == DiagnosticSeverity.Error);

                            foreach (Diagnostic diagnostic in failures)
                            {
                                message.AppendFormat("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
                            }

                            return new ReturnValue<MethodInfo>(false, "The following compile errors were encountered: " + message.ToString(), null);
                        }
                        else
                        {

                            ms.Seek(0, SeekOrigin.Begin);

 #if NET451
                            Assembly assembly = Assembly.Load(ms.ToArray());
 #else
                            AssemblyLoadContext context = AssemblyLoadContext.Default;
                            Assembly assembly = context.LoadFromStream(ms);
 #endif

                            Type mappingFunction = assembly.GetType("Program");
                            _functionMethod = mappingFunction.GetMethod("CustomFunction");
                            _resetMethod = mappingFunction.GetMethod("Reset");
                        }
                    }

在Windows上的.NET Core 2.2环境中,以前的答案都不适用于我。 需要更多参考。

所以在https://stackoverflow.com/a/39260735/710069解决方案的帮助下,我最终得到了这段代码:

var dotnetCoreDirectory = Path.GetDirectoryName(typeof(object).GetTypeInfo().Assembly.Location);

var compilation = CSharpCompilation.Create("LibraryName")
    .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
    .AddReferences(
        MetadataReference.CreateFromFile(typeof(object).GetTypeInfo().Assembly.Location),
        MetadataReference.CreateFromFile(typeof(Console).GetTypeInfo().Assembly.Location),
        MetadataReference.CreateFromFile(Path.Combine(dotnetCoreDirectory, "System.Runtime.dll")))
    .AddSyntaxTrees(CSharpSyntaxTree.ParseText(
        @"public static class ClassName 
        { 
            public static void MethodName() => System.Console.WriteLine(""Hello C# Compilation."");
        }"));

// Debug output. In case your environment is different it may show some messages.
foreach (var compilerMessage in compilation.GetDiagnostics())
    Console.WriteLine(compilerMessage);

比输出库到文件:

var fileName = "LibraryName.dll";
var emitResult = compilation.Emit(fileName);
if (emitResult.Success)
{
    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(Path.GetFullPath(fileName));

    assembly.GetType("ClassName").GetMethod("MethodName").Invoke(null, null);
}

或内存流:

using (var memoryStream = new MemoryStream())
{
    var emitResult = compilation.Emit(memoryStream);
    if (emitResult.Success)
    {
        memoryStream.Seek(0, SeekOrigin.Begin);

        var context = AssemblyLoadContext.Default;
        var assembly = context.LoadFromStream(memoryStream);

        assembly.GetType("ClassName").GetMethod("MethodName").Invoke(null, null);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM