Компиляция и выполнение кода во время выполнения in.Net ядро 1.0

можно ли компилировать и запускать код c# во время выполнения в новом .Net Core (лучшая платформа .Net Standard)? Я видел некоторые примеры (.Net Framework), но используемые пакеты NuGet есть

не совместим с netcoreapp1.0 (.NETCoreApp, версия=v1.0)

2 ответов


#1: используйте полный компилятор C# для компиляции сборки, загрузите ее, а затем выполните из нее метод.

для этого требуются следующие пакеты в качестве зависимостей в вашем проекте.в 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. Это приведет к гораздо более простому коду, но в настоящее время требует дополнительной настройки:

  • Создать NuGet.config, чтобы получить пакеты из ночной ленты Roslyn:

    <?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 (устаревший "целевой фреймворк",хотя по-прежнему используется Рослин):

    "frameworks": {
      "netcoreapp1.0": {
        "imports": "dotnet5.6"
      }
    }
    
  • теперь вы можете, наконец, использовать Сценарии:

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