2016-05-30 3 views

Antwort

15

Option # 1: Verwenden Sie den vollständigen C# -Compiler zum Kompilieren einer Assembly, laden Sie sie und führen Sie eine Methode daraus aus.

Dies erfordert die folgenden Pakete als Abhängigkeiten in Ihrem project.json:

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

Dann können Sie folgenden Code verwenden:

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

Option # 2: Verwenden Sie Roslyn Scripting. Dies wird in vielen einfachen Code führt, erfordert aber noch mehr Setup:

  • NuGet.config erstellen Pakete aus dem Roslyn nächtlichen FEED um:

    <?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> 
    
  • Fügen Sie das folgende Paket als Abhängigkeit project.json (man beachte, dass dieses Paket von heute ist, werden Sie andere Version in der Zukunft brauchen):

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

    Sie müssen auch dotnet importieren (Veraltet "Target Framework Moniker", which is nevertheless still used by Roslyn):

    "frameworks": { 
        "netcoreapp1.0": { 
        "imports": "dotnet5.6" 
        } 
    } 
    
  • Jetzt können Sie endlich Scripting verwenden:

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

Vielen Dank! – Mottor

+0

Kannst du meine andere Frage sehen? http://stackoverflow.com/questions/37482955/how-can-i-use-net-core-class-library-netstandard-v1-5-into-net-framework-4 – Mottor

+0

Ihr Beispiel funktioniert gut, aber es ist Es ist nicht möglich, 'ReadLine' oder' WriteLine' mit Parametern hinzuzufügen. Wo kann ich Dokumentation darüber bekommen, welche Überladungen und Methoden existieren? Weil es sehr komisch ist, wenn die Konsole Write-Methoden hat, aber keine ReadLine hat. –

8

einfach das Hinzufügen Option eine Antwort auf @svick. Wenn Sie die Baugruppe im Speicher behalten wollen (anstatt in eine Datei) einzugeben, können Sie die folgende Methode verwenden:

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

Dies unterscheidet, dass in Net451, wo der Code ist:

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

Meine Code zielt sowohl auf Net451 als auch auf Netstandard ab, daher musste ich Direktiven verwenden, um dieses Problem zu umgehen. Das vollständige Codebeispiel ist hier:

    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' existiert nicht in' .Net Core' –

+4

@AlexZhukovskiy 'AssemblyLoadContext' existiert * nur * in .Net Core, im 'System.Runtime.Loader'-Paket. – svick