Memo: Roslynを使ってC#のコードでC#のコードをコンパイルするの続きで、コンパイル結果をインメモリで取得して、そこからリフレクションを使ってインスタンスを作成する方法と、コンパイルエラー処理を追加。
using System; using System.Collections.Generic; using System.Text; using System.IO; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; using System.Reflection; namespace RoslynComple { class Program { // デフォルトして使用するネームスペースを定義 private static readonly List<string> DefaultNamepaces = new List<string> { "System", "System.IO", "System.Net", "System.Linq", "System.Text", "System.Text.RegularExpressions", "System.Collections.Generic" }; // デフォルトで使用する参照アセンブリの設定 private static string runtimePath = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\{0}.dll"; private static readonly List<MetadataReference> DefaultRefrences = new List<MetadataReference> { MetadataReference.CreateFromFile(string.Format(runtimePath, "mscorlib")), MetadataReference.CreateFromFile(string.Format(runtimePath, "System")), MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Core")) }; // DLLを出力、オーバーフローチェックはする、最適化オプションはRelease、 // 先に定義したネームスペースをデフォルトとのネームスペースとして使用、 // 決定論的コンパイラの出力をON private static readonly CSharpCompilationOptions DefaultCompletionOpsions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) .WithOverflowChecks(true).WithOptimizationLevel(OptimizationLevel.Release) .WithUsings(DefaultNamepaces).WithDeterministic(true); // パース処理の定義 public static SyntaxTree Parse(string text, string filename = "", CSharpParseOptions options = null) { var stringText = SourceText.From(text, Encoding.UTF8); return SyntaxFactory.ParseSyntaxTree(stringText, options, filename); } static void Main(string[] args) { // DLL Source Code var fileToCompile = @"C:\temp\Test.cs"; var source = File.ReadAllText(fileToCompile); // パースのオプションとしてC# 7.3を使用するように指定 var parseSyntaxTree = Parse(source, fileToCompile, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp7_3)); var compliation = CSharpCompilation.Create("Test", new SyntaxTree[] { parseSyntaxTree }, DefaultRefrences, DefaultCompletionOpsions); //コンパイル結果をファイルに出力する。 var dllFileName = @"c:\temp\Test.dll"; try { var result = compliation.Emit(dllFileName); Console.WriteLine(result.Success ? "Sucess!!" : "Failed"); } catch (Exception ex) { Console.WriteLine(ex); throw; } // コンパイル結果をメモリーストリームに出力し、そのコンパイル結果からインスタンスを作成する。 object instance; using (var ms = new MemoryStream()) { try { var result = compliation.Emit(ms); Console.WriteLine(result.Success ? "Sucess!!" : "Failed"); if (!result.Success) { foreach (var diag in result.Diagnostics) { // コンパイルエラーメッセージを表示 Console.WriteLine(diag.ToString()); // 以下でコンパイルエラーメッセージだけ取れそうだが、返ってくるのは空文字 Console.WriteLine("Description :" + diag.Descriptor.Description.ToString()); } Console.Read(); return; } ms.Seek(0, SeekOrigin.Begin); var assembly = Assembly.Load(ms.ToArray()); //instance = assembly.CreateInstance("TEST.Test", true); var types = assembly.GetExportedTypes(); instance = assembly.CreateInstance(types[0].FullName); } catch (Exception ex) { Console.WriteLine(ex); throw; } } Console.WriteLine(instance.GetType()); Console.Read(); } } }
Descriptorオブジェクトの中身が空なのが謎。
2020/11/24 コード内容の一部変更、コメントの追加。誰得?オレ特。
コメント