/// <summary> /// 使用内存流进行脚本编译 /// </summary> /// <param name="content">脚本内容</param> /// <param name="errorAction">发生错误执行委托</param> /// <returns></returns> public static Assembly StreamComplier(string content, Action <Diagnostic> errorAction = null) { content = content.Trim(); var(Tree, ClassName, formatter) = GetTreeAndClassNames(content); StringBuilder recoder = new StringBuilder(formatter); //创建语言编译 CSharpCompilation compilation = CSharpCompilation.Create( ClassName[0], options: new CSharpCompilationOptions( outputKind: OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release), syntaxTrees: new[] { Tree }, references: References); //编译并生成程序集 using (MemoryStream stream = new MemoryStream()) { var fileResult = compilation.Emit(stream); if (fileResult.Success) { stream.Position = 0; AssemblyLoadContext context = AssemblyLoadContext.Default; var result = context.LoadFromStream(stream); if (NScriptLog.UseLog) { recoder.AppendLine("\r\n\r\n------------------------------------------succeed-------------------------------------------"); recoder.AppendLine($"\r\n Time :\t\t{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); recoder.AppendLine($"\r\n Lauguage :\t{compilation.Language} & {compilation.LanguageVersion}"); recoder.AppendLine($"\r\n Target :\t\t{ClassName}"); recoder.AppendLine($"\r\n Size :\t\t{stream.Length}"); recoder.AppendLine($"\r\n Assembly : \t{result.FullName}"); recoder.AppendLine("\r\n----------------------------------------------------------------------------------------------"); NScriptLog.Succeed("Succeed : " + ClassName, recoder.ToString()); } return(result); } else { if (NScriptLog.UseLog) { recoder.AppendLine("\r\n\r\n------------------------------------------error----------------------------------------------"); recoder.AppendLine($"\r\n Time :\t\t{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); recoder.AppendLine($"\r\n Lauguage :\t{compilation.Language} & {compilation.LanguageVersion}"); recoder.AppendLine($"\r\n Target:\t\t{ClassName}"); recoder.AppendLine($"\r\n Error:\t\t共{fileResult.Diagnostics.Length}处错误!"); } //错误处理 foreach (var item in fileResult.Diagnostics) { if (NScriptLog.UseLog) { var temp = item.Location.GetLineSpan().StartLinePosition; var result = GetErrorString(formatter, item.Location.GetLineSpan()); recoder.AppendLine($"\t\t第{temp.Line + 1}行,第{temp.Character}个字符: 内容【{result}】 {item.GetMessage()}"); } errorAction?.Invoke(item); } if (NScriptLog.UseLog) { recoder.AppendLine("\r\n---------------------------------------------------------------------------------------------"); NScriptLog.Error("Error : " + ClassName, recoder.ToString()); } } } return(null); }
/// <summary> /// 使用文件流进行脚本编译,根据类名生成dll /// </summary> /// <param name="content">脚本内容</param> /// <param name="errorAction">发生错误执行委托</param> /// <returns></returns> public static Assembly FileComplier(string content, Action <Diagnostic> errorAction = null) { StringBuilder recoder = new StringBuilder(LineFormat(ref content)); //类名获取 var(Tree, ClassNames) = GetTreeAndClassNames(content); //生成路径 string path = $"{LibPath}{ClassNames[0]}.dll"; if (DynamicDlls.ContainsKey(path)) { return(DynamicDlls[path]); } //写入分析树 //SyntaxTree tree = SyntaxFactory.ParseSyntaxTree(content); //创建语言编译 CSharpCompilation compilation = CSharpCompilation.Create( ClassNames[0], options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary), syntaxTrees: new[] { Tree }, references: References); EmitResult fileResult; //编译到文件 try { fileResult = compilation.Emit(path); } catch (Exception ex) { if (ex is IOException) { int loop = 0; while (!DynamicDlls.ContainsKey(path)) { Thread.Sleep(200); loop += 1; } NScriptLog.Warning(ClassNames[0], $" I/O Delay :\t检测到争用,延迟{loop * 200}ms调用;\r\n"); return(DynamicDlls[path]); } return(null); } if (fileResult.Success) { References.Add(MetadataReference.CreateFromFile(path)); //为了实现动态中的动态,使用文件加载模式常驻内存 var result = Assembly.LoadFrom(path); for (int i = 0; i < ClassNames.Length; i += 1) { ClassMapping[ClassNames[i]] = result; } if (NScriptLog.UseLog) { recoder.AppendLine("\r\n\r\n------------------------------------------succeed-------------------------------------------"); recoder.AppendLine($"\r\n Lauguage :\t{compilation.Language}___{compilation.LanguageVersion}"); recoder.AppendLine($"\r\n Target :\t\t{ClassNames[0]}"); recoder.AppendLine($"\r\n Path :\t\t{path}"); recoder.AppendLine($"\r\n Assembly : \t{result.FullName}"); recoder.AppendLine("\r\n----------------------------------------------------------------------------------------------"); NScriptLog.Succeed("Succeed : " + ClassNames[0], recoder.ToString()); } DynamicDlls[path] = result; return(result); } else { if (NScriptLog.UseLog) { recoder.AppendLine("\r\n\r\n------------------------------------------error----------------------------------------------"); recoder.AppendLine($"\r\n Lauguage :\t{compilation.Language}___{compilation.LanguageVersion}"); recoder.AppendLine($"\r\n Target:\t\t{ClassNames[0]}"); recoder.AppendLine($"\r\n Error:\t\t共{fileResult.Diagnostics.Length}处错误!"); } foreach (var item in fileResult.Diagnostics) { if (NScriptLog.UseLog) { var temp = item.Location.GetLineSpan().StartLinePosition; var result = GetErrorString(content, item.Location.GetLineSpan()); recoder.AppendLine($"\t\t第{temp.Line}行,第{temp.Character}个字符: 内容【{result}】 {item.GetMessage()}"); } errorAction?.Invoke(item); } recoder.AppendLine("\r\n---------------------------------------------------------------------------------------------"); NScriptLog.Error("Error : " + ClassNames[0], recoder.ToString()); } return(null); }
/// <summary> /// 使用文件流进行脚本编译,根据类名生成dll /// </summary> /// <param name="content">脚本内容</param> /// <param name="errorAction">发生错误执行委托</param> /// <returns></returns> public static Assembly FileComplier(string content, Action <Diagnostic> errorAction = null) { //类名获取 content = content.Trim(); var(Tree, ClassNames, formatter) = GetTreeAndClassNames(content); StringBuilder recoder = new StringBuilder(FormatLineCode(formatter)); //生成路径 string path = Path.Combine(LibPath, $"{ClassNames[0]}.dll"); if (DynamicDlls.ContainsKey(path)) { return(DynamicDlls[path]); } //创建语言编译 CSharpCompilation compilation = CSharpCompilation.Create( ClassNames[0], options: new CSharpCompilationOptions( outputKind: OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release), syntaxTrees: new[] { Tree }, references: References); EmitResult fileResult; //编译到文件 try { fileResult = compilation.Emit(path); if (fileResult.Success) { //为了实现动态中的动态,使用文件加载模式常驻内存 AssemblyLoadContext context = AssemblyLoadContext.Default; var result = context.LoadFromAssemblyPath(path); References.Add(MetadataReference.CreateFromFile(path)); for (int i = 0; i < ClassNames.Length; i += 1) { ClassMapping[ClassNames[i]] = result; } if (NScriptLog.UseLog) { recoder.AppendLine("\r\n\r\n------------------------------------------succeed-------------------------------------------"); recoder.AppendLine($"\r\n Time :\t\t{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); recoder.AppendLine($"\r\n Lauguage :\t{compilation.Language} & {compilation.LanguageVersion}"); recoder.AppendLine($"\r\n Target :\t\t{ClassNames[0]}"); recoder.AppendLine($"\r\n Path :\t\t{path}"); recoder.AppendLine($"\r\n Assembly : \t{result.FullName}"); recoder.AppendLine("\r\n----------------------------------------------------------------------------------------------"); NScriptLog.Succeed("Succeed : " + ClassNames[0], recoder.ToString()); } DynamicDlls[path] = result; return(result); } else { if (NScriptLog.UseLog) { recoder.AppendLine("\r\n\r\n------------------------------------------error----------------------------------------------"); recoder.AppendLine($"\r\n Time :\t\t{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}"); recoder.AppendLine($"\r\n Lauguage :\t{compilation.Language} & {compilation.LanguageVersion}"); recoder.AppendLine($"\r\n Target:\t\t{ClassNames[0]}"); recoder.AppendLine($"\r\n Error:\t\t共{fileResult.Diagnostics.Length}处错误!"); } foreach (var item in fileResult.Diagnostics) { if (NScriptLog.UseLog) { var temp = item.Location.GetLineSpan().StartLinePosition; var result = GetErrorString(formatter, item.Location.GetLineSpan()); recoder.AppendLine($"\t\t第{temp.Line + 1}行,第{temp.Character}个字符: 内容【{result}】 {item.GetMessage()}"); } errorAction?.Invoke(item); } recoder.AppendLine("\r\n---------------------------------------------------------------------------------------------"); NScriptLog.Error("Error : " + ClassNames[0], recoder.ToString()); } return(null); } catch (Exception ex) { if (ex is IOException) { int loop = 0; while (!DynamicDlls.ContainsKey(path)) { Thread.Sleep(200); loop += 1; } NScriptLog.Warning(ClassNames[0], $" I/O Delay :\t检测到争用,延迟{loop * 200}ms调用;\r\n"); return(DynamicDlls[path]); } return(null); } }
/// <summary> /// 使用内存流进行脚本编译 /// </summary> /// <param name="content">脚本内容</param> /// <param name="errorAction">发生错误执行委托</param> /// <returns></returns> public static Assembly StreamComplier(string content, Action <Diagnostic> errorAction = null) { StringBuilder recoder = new StringBuilder(LineFormat(ref content)); var(Tree, ClassName) = GetTreeAndClassName(content); //创建语言编译 CSharpCompilation compilation = CSharpCompilation.Create( ClassName, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary), syntaxTrees: new[] { Tree }, references: References); //编译并生成程序集 using (MemoryStream stream = new MemoryStream()) { var fileResult = compilation.Emit(stream); if (fileResult.Success) { var result = Assembly.Load(stream.GetBuffer()); if (NScriptLog.UseLog) { recoder.AppendLine("\r\n\r\n------------------------------------------succeed-------------------------------------------"); recoder.AppendLine($"\r\n Lauguage :\t{compilation.Language}___{compilation.LanguageVersion}"); recoder.AppendLine($"\r\n Target :\t\t{ClassName}"); recoder.AppendLine($"\r\n Size :\t\t{stream.Length}"); recoder.AppendLine($"\r\n Assembly : \t{result.FullName}"); recoder.AppendLine("\r\n----------------------------------------------------------------------------------------------"); NScriptLog.Succeed("Succeed : " + ClassName, recoder.ToString()); } return(result); } else { if (NScriptLog.UseLog) { recoder.AppendLine("\r\n\r\n------------------------------------------error----------------------------------------------"); recoder.AppendLine($"\r\n Lauguage :\t{compilation.Language}___{compilation.LanguageVersion}"); recoder.AppendLine($"\r\n Target:\t\t{ClassName}"); recoder.AppendLine($"\r\n Error:\t\t共{fileResult.Diagnostics.Length}处错误!"); } //错误处理 foreach (var item in fileResult.Diagnostics) { if (NScriptLog.UseLog) { var temp = item.Location.GetLineSpan().StartLinePosition; var result = GetErrorString(content, item.Location.GetLineSpan()); recoder.AppendLine($"\t\t第{temp.Line}行,第{temp.Character}个字符: 内容【{result}】 {item.GetMessage()}"); } errorAction?.Invoke(item); } if (NScriptLog.UseLog) { recoder.AppendLine("\r\n---------------------------------------------------------------------------------------------"); NScriptLog.Error("Error : " + ClassName, recoder.ToString()); } } } return(null); }