2016-05-30 25 views

Odpowiedz

15

Option # 1: Użyj pełnego kompilatora C#, aby skompilować złożenie, załaduj go, a następnie uruchom z niego metodę.

Wymaga to następujące pakiety jako zależności w swojej project.json:

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

Następnie można użyć kodu:

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

Opcja nr 2 Use Roslyn skryptów. Spowoduje to znacznie prostszy kod, ale obecnie wymaga więcej Setup:

  • Tworzenie NuGet.config dostać paczki z Roslyn nocnej paszy:

    <?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> 
    
  • Dodaj następujący pakiet jako zależność do project.json (zauważ, że jest to pakiet od dzisiaj, trzeba będzie inna wersja w przyszłości):

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

    należy również importować dotnet (Przestarzałe "docelowa ramowa Moniker" which is nevertheless still used by Roslyn):

    "frameworks": { 
        "netcoreapp1.0": { 
        "imports": "dotnet5.6" 
        } 
    } 
    
  • Teraz można wreszcie używać skryptów:

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

Dziękuję bardzo! – Mottor

+0

Czy widzisz moje inne pytanie? http://stackoverflow.com/questions/37482955/how-can-i-use-net-core-class-library-netstandard-v1-5-into-net-framework-4 – Mottor

+0

Twój przykład działa dobrze, jednak jest nie można dodać 'ReadLine' lub' WriteLine' z parametrami. Gdzie mogę uzyskać dokumentację dotyczącą przeciążenia i metod? Ponieważ jest bardzo dziwne, gdy Console ma metody Write, ale nie ma żadnej ReadLine. –

8

wystarczy dodać do @svick Opcja pierwsza odpowiedź. Jeśli chcesz, aby utrzymać zespół w pamięci (zamiast zapisywania do pliku) można wykorzystać następujące metody:

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

Inaczej jest, że w Net451 gdzie kod to:

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

My Kod jest kierowany zarówno na Net451, jak i Netstandard, więc musiałem użyć dyrektyw, aby obejść ten problem. Pełny przykład kodu znajduje się tutaj:

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

' AssemblyLoadContext' nie istnieje w '.Net Core' –

+4

@AlexZhukovskiy' AssemblyLoadContext' istnieje * tylko * w .Net Core, w pakiecie 'System.Runtime.Loader'. – svick

Powiązane problemy