From 152d892e8add80b53ea260b35b6b09de2a04bafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=9C=A8=E6=A3=AE=20=C2=B7=20=E4=BD=9C=E9=9C=96?= <16236903+NMSAzulX@users.noreply.github.com> Date: Tue, 28 May 2024 20:24:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=92=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E9=83=A8=E5=88=86=E6=96=B9=E6=B3=95=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AssemblyCSharpBuilder.Compile.cs | 190 ++++++++++++------ .../AssemblyCSharpBuilder.CompileOption.cs | 87 ++++++-- .../AssemblyCSharpBuilder.LoadContext.cs | 32 ++- .../CompileUnit/AssemblyCSharpBuilder.Log.cs | 15 +- .../AssemblyCSharpBuilder.Ouput.cs | 9 +- .../AssemblyCSharpBuilder.Semantic.cs | 14 +- .../AssemblyCSharpBuilder.Syntax.cs | 29 ++- .../CompileUnit/AssemblyCSharpBuilder.cs | 24 ++- .../SemanticAnalaysis/UsingAnalysistor.cs | 11 +- .../Compiler/NatashaCSharpCompilerOptions.cs | 2 +- .../Compiler/Utils/RuntimeInnerHelper.cs | 2 +- .../NatashaAssemblyBuilderExtension.cs | 56 +++++- 12 files changed, 345 insertions(+), 126 deletions(-) diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Compile.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Compile.cs index 6c40b66a..d9f13146 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Compile.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Compile.cs @@ -1,7 +1,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Emit; -using Microsoft.Extensions.DependencyModel; using Natasha.CSharp.Compiler.Component; using Natasha.CSharp.Compiler.Component.Exception; using Natasha.CSharp.Extension.Inner; @@ -12,7 +11,6 @@ using System.Diagnostics; using System.IO; using System.Reflection; -using System.Text; /// /// 程序集编译构建器 - 编译选项 /// @@ -24,10 +22,21 @@ public sealed partial class AssemblyCSharpBuilder /// - /// 编译时,使用主域引用覆盖引用集,并配置同名引用版本行为(默认优先使用主域引用) + /// 该方法允许共享域参与编译. + /// + /// + /// [共享域] 元数据参与编译. + /// + /// + /// [当前域] 元数据参与编译. + /// + /// /// - /// 配置委托 - /// + /// + /// 注:若两个域不同,且存在相同名称元数据,默认优先使用主域的元数据. + /// + /// 配置同名元数据的解决策略 + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithCombineReferences(Action? action = null) { action?.Invoke(_referenceConfiguration); @@ -35,10 +44,19 @@ public AssemblyCSharpBuilder WithCombineReferences(Action - /// 编译时,使用当前域引用来覆盖引用集 + /// 配置编译元数据的合并行为. + /// + /// + /// [共享域] 元数据 [不] 参与编译. + /// + /// + /// [当前域] 元数据参与编译. + /// + /// /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithCurrentReferences() { _combineReferenceBehavior = CombineReferenceBehavior.UseCurrent; @@ -47,10 +65,21 @@ public AssemblyCSharpBuilder WithCurrentReferences() private readonly List _specifiedReferences; /// - /// 使用外部指定的引用来覆盖引用集 + /// 使用外部指定的元数据引用进行编译. + /// + /// + /// [共享域] 元数据 [不] 参与编译. + /// + /// + /// [当前域] 元数据 [不] 参与编译. + /// + /// /// + /// + /// 使用 ClearOutsideReferences 可以清楚本次传递的元数据引用. + /// /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithSpecifiedReferences(IEnumerable metadataReferences) { lock (_specifiedReferences) @@ -60,6 +89,11 @@ public AssemblyCSharpBuilder WithSpecifiedReferences(IEnumerable + /// 清除由 WithSpecifiedReferences 方法传入的元数据引用. + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder ClearOutsideReferences() { lock (_specifiedReferences) @@ -71,10 +105,10 @@ public AssemblyCSharpBuilder ClearOutsideReferences() /// - /// 配置引用过滤策略 + /// 配置元数据引用过滤策略. /// /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder SetReferencesFilter(Func, IEnumerable>? referencesFilter) { _referencesFilter = referencesFilter; @@ -82,25 +116,39 @@ public AssemblyCSharpBuilder SetReferencesFilter(Func - /// 流编译成功之后触发的事件 + /// 流编译成功之后触发的事件. /// + /// + /// 此时已编译结束,程序集已经生成并加载. + /// public event Action? CompileSucceedEvent; - /// - /// 流编译失败之后触发的事件 + /// 流编译失败之后触发的事件. /// + /// + /// 此时已经编译结束, 但是编译失败. + /// public event Action>? CompileFailedEvent; - private ConcurrentQueue>? _emitOptionHandle; /// - /// 处理默认生成的 emitOption 并返回一个新的 + /// 追加对 emitOption 的处理逻辑. + /// + /// 一次性配置,不可重用. + /// 多次调用会进入配置队列. + /// 调用 后清空队列. + /// 调用 后清空队列. + /// 调用 后清空队列. + /// /// + /// + /// 注:该配置属于一次性配置,若重复使用该配置逻辑,请在这次编译后重新调用该方法. + /// /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder ConfigEmitOptions(Func handleAndReturnNewEmitOption) { _emitOptionHandle ??= new ConcurrentQueue>(); @@ -110,18 +158,18 @@ public AssemblyCSharpBuilder ConfigEmitOptions(Func ha private bool _notLoadIntoDomain; /// - /// 仅仅生成程序集,而不加载到域。 + /// 仅仅生成程序集,而不加载到域. /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithoutInjectToDomain() { _notLoadIntoDomain = true; return this; } /// - /// 既生成程序集又加载到域。 + /// 既生成程序集又加载到域(不用配置,默认行为). /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithInjectToDomain() { _notLoadIntoDomain = false; @@ -129,36 +177,42 @@ public AssemblyCSharpBuilder WithInjectToDomain() } /// - /// 将 SyntaxTrees 中的语法树编译到程序集.如果不成功会抛出 NatashaException. - /// - /// - /// + /// 编译并获取程序集. + /// + /// 编译后的信息获取 + /// + /// 获取编译配置载体. + /// 获取诊断结果. + /// 获取运行抛出的异常结果. + /// 监听成功编译结果. + /// 监听失败编译结果. /// - /// - /// //Core3.0以上版本 - /// //程序集的域加载行为决定了编译后的程序集随着依赖加载到域中的处理结果. - /// //编译单元支持的依赖加载方法: - /// WithHighVersionDependency - /// WithLowVersionDependency - /// WithDefaultVersionDependency - /// WithCustomVersionDependency - /// - /// //编译单元的引用加载行为, 遇到同名不同版本的引用该如何处理. - /// //首先启用合并引用,此方法将允许主域引用和当前域引用进行整合 - /// builder.WithCombineReferences(configAction); - /// //其参数支持同名引用的加载逻辑,包括 - /// config.UseHighVersionReferences - /// config.UseLowVersionReferences - /// config.UseDefaultReferences - /// config.UseCustomReferences - /// //手动设置同名过滤器 - /// config.ConfigSameNameReferencesFilter(func); - /// //手动设置全部引用过滤器 - /// builder.SetReferencesFilter - /// + /// builder.CompileFailedEvent += (compilation, errors) =>{ + /// log = compilation.GetNatashaLog(); + /// log.ToString(); + /// }; /// - /// + /// 监听编译日志. + /// + /// builder.LogCompilationEvent += (log) =>{ + /// //log.ToString(); + /// }; + /// + /// + /// + /// + /// 重复编译 + /// + /// 查看您所使用过的 Config 开头方法的注释. + /// 方法使 Builder 可以继续使用. + /// + /// + /// + /// + /// + /// 注:若不需要加载到域,需提前使用 WithoutInjectToDomain 方法. /// + /// 编译成功生成的程序集. public Assembly GetAssembly() { _compilation ??= GetAvailableCompilation(); @@ -167,8 +221,6 @@ public Assembly GetAssembly() Domain.SetAssemblyLoadBehavior(_domainConfiguration._dependencyLoadBehavior); } - - #if DEBUG Stopwatch stopwatch = new(); stopwatch.Start(); @@ -235,8 +287,7 @@ public Assembly GetAssembly() includePrivateMembers: _includePrivateMembers, metadataOnly: _isReferenceAssembly, pdbFilePath: PdbFilePath, - debugInformationFormat: debugInfoFormat - ); + debugInformationFormat: debugInfoFormat); if (_emitOptionHandle != null) { @@ -282,7 +333,8 @@ public Assembly GetAssembly() else { CompileFailedEvent?.Invoke(_compilation, compileResult.Diagnostics); - throw NatashaExceptionAnalyzer.GetCompileException(_compilation, compileResult.Diagnostics); + _exception = NatashaExceptionAnalyzer.GetCompileException(_compilation, compileResult.Diagnostics); + throw _exception; } dllStream.Dispose(); pdbStream?.Dispose(); @@ -294,8 +346,12 @@ public Assembly GetAssembly() return assembly!; } - - public unsafe (Assembly, byte[], byte[], byte[]) UpdateAssembly(Assembly oldAssembly) + /// + /// 热重载相关(未完成,无法使用) + /// + /// + /// + public unsafe Assembly UpdateAssembly(Assembly oldAssembly) { _compilation ??= GetAvailableCompilation(); if (Domain!.Name != "Default") @@ -388,24 +444,24 @@ public unsafe (Assembly, byte[], byte[], byte[]) UpdateAssembly(Assembly oldAsse var ilDelta = AsReadOnlySpan(dllStream); var pdbDelta = AsReadOnlySpan(pdbStream); var metadataDelta = AsReadOnlySpan(metaStream); - RuntimeInnerHelper.ApplyUpdate(oldAssembly, metadataDelta, ilDelta, pdbDelta); - return (oldAssembly!, metadataDelta.ToArray(), ilDelta.ToArray(), pdbDelta.ToArray()); + RuntimeInnerHelper.ApplyUpdate(oldAssembly, metadataDelta, ilDelta, null); + dllStream.Dispose(); + pdbStream.Dispose(); + metaStream.Dispose(); + xmlStream?.Dispose(); + return oldAssembly!; } else { + dllStream.Dispose(); + pdbStream.Dispose(); + metaStream.Dispose(); + xmlStream?.Dispose(); CompileFailedEvent?.Invoke(_compilation, compileResult.Diagnostics); - throw NatashaExceptionAnalyzer.GetCompileException(_compilation, compileResult.Diagnostics); + _exception = NatashaExceptionAnalyzer.GetCompileException(_compilation, compileResult.Diagnostics); + throw _exception; } - dllStream.Dispose(); - pdbStream.Dispose(); - metaStream.Dispose(); - xmlStream?.Dispose(); - -#if DEBUG - stopwatch.StopAndShowCategoreInfo("[ Emit ]", "编译时长", 2); -#endif - return default!; static ReadOnlySpan AsReadOnlySpan(Stream input) { diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.CompileOption.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.CompileOption.cs index c37ecb6c..23688b7e 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.CompileOption.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.CompileOption.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Dynamic; /// /// 程序集编译构建器 - 编译选项 /// @@ -14,13 +13,34 @@ public sealed partial class AssemblyCSharpBuilder private readonly NatashaCSharpCompilerOptions _compilerOptions; private CSharpCompilation? _compilation; public CSharpCompilation? Compilation { get { return _compilation; } } - + + /// + /// 配置编译选项. + /// + /// 复用 Builder 场景: + /// + /// + /// 该方法为一次性方法,配置不会被缓存. + /// + /// + /// 用 方法后,重调此方法并传入您的配置逻辑. + /// + /// + /// + /// + /// + /// 配置 [编译载体] 的逻辑. + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder ConfigCompilerOption(Action action) { action(_compilerOptions); return this; } + /// + /// 获取当前 [编译载体] 的诊断信息. + /// + /// 诊断信息集合 public ImmutableArray? GetDiagnostics() { return _compilation?.GetDiagnostics(); @@ -31,18 +51,21 @@ public AssemblyCSharpBuilder ConfigCompilerOption(Action - /// 输出文件包含私有字段信息 + /// 输出文件包含私有字段信息. /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithPrivateMembers() { _includePrivateMembers = true; return this; } /// - /// 输出文件不包含私有字段信息(默认) + /// 输出文件不包含私有字段信息(默认). /// - /// + /// + /// 注:选项状态会被缓存,复用时无需重复调用. + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithoutPrivateMembers() { _includePrivateMembers = false; @@ -50,9 +73,12 @@ public AssemblyCSharpBuilder WithoutPrivateMembers() } /// - /// 是否以引用程序集方式输出 + /// 是否以引用程序集方式输出. /// - /// + /// + /// 注:选项状态会被缓存,复用时无需重复调用. + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder OutputAsRefAssembly() { _isReferenceAssembly = true; @@ -60,9 +86,12 @@ public AssemblyCSharpBuilder OutputAsRefAssembly() return this; } /// - /// 是否以完全程序集方式输出(默认) + /// 是否以完全程序集方式输出(默认). /// - /// + /// + /// 注:选项状态会被缓存,复用时无需重复调用. + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder OutputAsFullAssembly() { _isReferenceAssembly = false; @@ -74,9 +103,12 @@ public AssemblyCSharpBuilder OutputAsFullAssembly() private OptimizationLevel _codeOptimizationLevel; /// - /// 编译时使用 Debug 模式 + /// 编译时使用 Debug 模式. /// - /// + /// + /// 注:选项状态会被缓存,复用时无需重复调用. + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithDebugCompile(Action? action = null) { action?.Invoke(_debugConfiguration); @@ -84,9 +116,12 @@ public AssemblyCSharpBuilder WithDebugCompile(Action? action return this; } /// - /// 编译时使用 Release 模式优化(默认) + /// 编译时使用 Release 模式优化(默认). /// - /// + /// + /// 注:选项状态会被缓存,复用时无需重复调用. + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithReleaseCompile() { _withDebugInfo = false; @@ -94,9 +129,12 @@ public AssemblyCSharpBuilder WithReleaseCompile() return this; } /// - /// 编译时使用携带有 DebugInfo 的 Release 模式优化(默认) + /// 编译时使用携带有 DebugInfo 的 Release 模式优化(默认). /// - /// + /// + /// 注:选项状态会被缓存,复用时无需重复调用. + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithFullReleaseCompile() { _withDebugInfo = true; @@ -104,7 +142,22 @@ public AssemblyCSharpBuilder WithFullReleaseCompile() return this; } - + /// + /// 获取一个配置好的 [编译载体]. + /// + /// + /// 语法树已经完成格式化. + /// + /// + /// 语法树已经完成语义过滤(若开启). + /// + /// + /// 元数据已经填充完毕. + /// + /// + /// + /// + /// 编译载体. public CSharpCompilation GetAvailableCompilation(Func? initOptionsFunc = null) { diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.LoadContext.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.LoadContext.cs index 314dbcea..46c05da7 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.LoadContext.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.LoadContext.cs @@ -1,6 +1,5 @@ using Natasha.DynamicLoad.Base; using System; -using System.Runtime.CompilerServices; /// /// 程序集编译构建器 - 域 @@ -11,8 +10,23 @@ public sealed partial class AssemblyCSharpBuilder private readonly DomainConfiguration _domainConfiguration; /// - /// 配置上下文 + /// 配置加载上下文,并立即生效. + /// + /// 复用 Builder 场景: + /// + /// + /// 没有需要处理的,除非想重新创建一个上下文. + /// + /// + /// 别在同一个域创建同名程序集. + /// + /// + /// + /// /// + /// + /// 注:[加载上下文] 的内容包括该域成功编译后产生的 [元数据引用]、[UsingCode]. + /// /// /// public AssemblyCSharpBuilder ConfigLoadContext(Func handle) @@ -22,7 +36,7 @@ public AssemblyCSharpBuilder ConfigLoadContext(Func - /// 编译单元所在的上下文 + /// 编译单元所在的上下文. /// public NatashaLoadContext LoadContext { @@ -36,18 +50,20 @@ public NatashaLoadContext LoadContext } } /// - /// 编译单元所在域.该域实现了 INatashaDynamicLoadContextBase 接口,并由 INatashaDynamicLoadContextCreator 接口实现创建而来 + /// 编译单元所在域.该域实现了 INatashaDynamicLoadContextBase 接口,并由 INatashaDynamicLoadContextCreator 接口实现创建而来. /// public INatashaDynamicLoadContextBase Domain { get { return _loadContext.Domain; } } - /// - /// 配置域 + /// 配置域,并立即生效. /// - /// - /// + /// + /// 注:选项状态会被缓存,复用时无需重复调用. + /// + /// 配置逻辑 + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder ConfigDomain(Action action) { action(_domainConfiguration); diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Log.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Log.cs index 6baf6501..a3ecdfa5 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Log.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Log.cs @@ -2,8 +2,21 @@ public sealed partial class AssemblyCSharpBuilder { - + /// + /// 监听编译日志事件,默认不监听. + /// + /// + /// 注:该事件会被缓存,复用时无需重复添加方法. + /// public event Action? LogCompilationEvent; + /// + /// 和使用 += log =>{} 一样. + /// + /// + /// 注:该事件会被缓存,复用时无需重复添加方法. + /// + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder SetLogEvent(Action logAction) { LogCompilationEvent = logAction; diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs index 9b2f4aad..2a484f2d 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Ouput.cs @@ -28,6 +28,11 @@ static AssemblyCSharpBuilder() } + /// + /// 设置程序集名称 + /// + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder SetAssemblyName(string asmName) { AssemblyName = asmName; @@ -40,7 +45,7 @@ public AssemblyCSharpBuilder SetAssemblyName(string asmName) /// /// /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithFileOutput(string dllFilePath, string? pdbFilePath = null, string? commentFilePath = null) { if (dllFilePath!=string.Empty) @@ -81,7 +86,7 @@ public AssemblyCSharpBuilder WithFileOutput(string dllFilePath, string? pdbFileP /// 默认不输出到文件,只输出到内存。 /// /// 文件夹路径 - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithFileOutput(string? folder = null) { if (folder == null) diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Semantic.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Semantic.cs index 53849e7c..ed2b7ca3 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Semantic.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Semantic.cs @@ -15,7 +15,7 @@ public sealed partial class AssemblyCSharpBuilder /// /// 语义检查时,开启访问性检查 /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithAnalysisAccessibility() { _semanticCheckIgnoreAccessibility = false; @@ -25,7 +25,7 @@ public AssemblyCSharpBuilder WithAnalysisAccessibility() /// /// 语义检查时,关闭访问性检查 /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithoutAnalysisAccessibility() { _semanticCheckIgnoreAccessibility = true; @@ -35,7 +35,7 @@ public AssemblyCSharpBuilder WithoutAnalysisAccessibility() /// 添加语义处理器 /// /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder AddSemanticAnalysistor(Func func) { _semanticAnalysistor.Add(func); @@ -45,7 +45,7 @@ public AssemblyCSharpBuilder AddSemanticAnalysistor(Func /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder RemoveSemanticAnalysistor(Func func) { _semanticAnalysistor.Remove(func); @@ -56,7 +56,7 @@ public AssemblyCSharpBuilder RemoveSemanticAnalysistor(Func /// 开启语义检测, 若预热,则自动开启。 /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithoutSemanticCheck() { @@ -66,7 +66,7 @@ public AssemblyCSharpBuilder WithoutSemanticCheck() /// /// 关闭语义检测,默认:若预热则为开启,否则是关闭。 /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder WithSemanticCheck() { EnableSemanticHandler = true; @@ -76,7 +76,7 @@ public AssemblyCSharpBuilder WithSemanticCheck() /// /// 清除当前编译单元所有的语义处理器 /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder ClearInnerSemanticAnalysistor() { _semanticAnalysistor.Remove(UsingAnalysistor._usingSemanticDelegate); diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Syntax.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Syntax.cs index 1d8df95a..40db2542 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Syntax.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.Syntax.cs @@ -16,9 +16,10 @@ public sealed partial class AssemblyCSharpBuilder private CSharpParseOptions? _options; private UsingLoadBehavior _parsingBehavior; /// - /// 配置语法树选项 + /// 配置语法树选项. + /// (注:该方法为一次性方法,使用过 Clear 方法后需要重新调用以达到您预期的配置) /// - /// + /// 直接传入语法树选项 /// public AssemblyCSharpBuilder ConfigSyntaxOptions(CSharpParseOptions cSharpParseOptions) { @@ -27,8 +28,9 @@ public AssemblyCSharpBuilder ConfigSyntaxOptions(CSharpParseOptions cSharpParseO } /// /// 配置语法树选项 + /// (注:该方法为一次性方法,使用过 Clear 方法后需要重新调用以达到您预期的配置) /// - /// + /// 传入语法树配置逻辑 /// public AssemblyCSharpBuilder ConfigSyntaxOptions(Func cSharpParseOptionsAction) { @@ -55,10 +57,10 @@ public AssemblyCSharpBuilder WithoutCombineUsingCode() /// /// 注入代码并拼接using,拼接 using 的逻辑与 WithCombineUsingCode 方法设置有关. - /// 在开启预热后,将自动拼接主域与当前域的 using. + /// (注:在开启预热后,将自动拼接主域与当前域的 using.) /// /// C#代码 - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder Add(string script) { return Add(script, _parsingBehavior); @@ -68,12 +70,14 @@ public AssemblyCSharpBuilder Add(string script) /// 添加脚本 /// /// + /// 链式对象(调用方法的实例本身). private AssemblyCSharpBuilder AddScript(string script) { var tree = NatashaCSharpSyntax.ParseTree(script, _options); var exception = NatashaExceptionAnalyzer.GetSyntaxException(tree); if (exception != null) { + _exception = exception; throw exception; } else @@ -87,10 +91,10 @@ private AssemblyCSharpBuilder AddScript(string script) } /// - /// 快速添加语法树,无检查 + /// 快速添加语法树,无检查. /// /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder FastAddScriptWithoutCheck(string script) { SyntaxTrees.Add(NatashaCSharpSyntax.ParseTree(script, _options)); @@ -98,9 +102,11 @@ public AssemblyCSharpBuilder FastAddScriptWithoutCheck(string script) } /// - /// 添加语法树 + /// 添加语法树. + /// (注:如果希望跳过检查和格式化,可以使用 FastAddScriptWithoutCheck 方法.) /// /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder Add(SyntaxTree tree) { tree = NatashaCSharpSyntax.FormartTree(tree, _options); @@ -118,7 +124,10 @@ public AssemblyCSharpBuilder Add(SyntaxTree tree) } return this; } - + /// + /// 清除编译单元内的语法树 + /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder ClearScript() { SyntaxTrees.Clear(); @@ -130,7 +139,7 @@ public AssemblyCSharpBuilder ClearScript() /// /// C#代码 /// using 拼接行为 - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder Add(string script, UsingLoadBehavior usingLoadBehavior) { switch (usingLoadBehavior) diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.cs index d3f3da62..1ecc06db 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/AssemblyCSharpBuilder.cs @@ -11,6 +11,12 @@ [assembly: InternalsVisibleTo("Natasha.CSharp.UnitTest.Base, PublicKey=002400000480000094000000060200000024000052534131000400000100010069acb31dd0d9918441d6ed2b49cd67ae17d15fd6ded4ccd2f99b4a88df8cddacbf72d5897bb54f406b037688d99f482ff1c3088638b95364ef614f01c3f3f2a2a75889aa53286865463fb1803876056c8b98ec57f0b3cf2b1185de63d37041ba08f81ddba0dccf81efcdbdc912032e8d2b0efa21accc96206c386b574b9d9cb8")] public sealed partial class AssemblyCSharpBuilder { + private NatashaException? _exception; + + public NatashaException? GetException() + { + return _exception; + } public AssemblyCSharpBuilder() : this(Guid.NewGuid().ToString("N")) { @@ -37,14 +43,23 @@ public AssemblyCSharpBuilder(string assemblyName) internal static bool HasInitialized; /// - /// 清空编译信息, 下次编译重组 Compilation . + /// 清空编译载体信息, 下次编译重组 Compilation . /// - /// + /// 链式对象(调用方法的实例本身). public AssemblyCSharpBuilder ClearCompilationCache() { _compilation = null; return this; } + /// + /// 清空 emitOption 配置逻辑. + /// + /// 链式对象(调用方法的实例本身). + public AssemblyCSharpBuilder ClearEmitOptionCache() + { + _emitOptionHandle = null; + return this; + } /// /// 清空所有记录,包括编译信息和脚本记录,以及程序集名称. @@ -53,6 +68,7 @@ public AssemblyCSharpBuilder ClearCompilationCache() public AssemblyCSharpBuilder Clear() { _compilation = null; + _emitOptionHandle = null; SyntaxTrees.Clear(); AssemblyName = string.Empty; return this; @@ -70,7 +86,7 @@ public AssemblyCSharpBuilder WithRandomAssenblyName() } /// - /// 轻便模式:无合并行为,使用当前域的 Using,无语义检查 + /// 轻便模式:无合并行为,仅使用当前域的元数据、Using,无语义检查. /// /// public AssemblyCSharpBuilder UseSimpleMode() @@ -84,7 +100,7 @@ public AssemblyCSharpBuilder UseSimpleMode() return this; } /// - /// 智能模式:默认合并所有元数据,合并当前域及主域 Using,开启语义检查 + /// 智能模式:合并当前域及主域 的元数据、Using,开启语义检查. /// /// public AssemblyCSharpBuilder UseSmartMode() diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/SemanticAnalaysis/UsingAnalysistor.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/SemanticAnalaysis/UsingAnalysistor.cs index 5228ba0b..35b52411 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/SemanticAnalaysis/UsingAnalysistor.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/CompileUnit/SemanticAnalaysis/UsingAnalysistor.cs @@ -51,12 +51,13 @@ static UsingAnalysistor() { var error = errors[i]; //NamespaceName2 中的命名空间 NamespaceName1 与 NamespaceName3 中的类型 TypeName1 冲突 - if (error.Id == "CS0434") - { - error.RemoveDefaultUsingAndUsingNode(root, errorNodes); - } + //if (error.Id == "CS0434") + //{ + // error.RemoveDefaultUsingAndUsingNode(root, errorNodes); + //} //无用 using , 不必要的 using 指令。 - else if (error.Id == "CS8019") + //else + if (error.Id == "CS8019") { var node = error.GetTypeSyntaxNode(root); if (node != null) diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/NatashaCSharpCompilerOptions.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/NatashaCSharpCompilerOptions.cs index 5aecfee1..15f2ab07 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/NatashaCSharpCompilerOptions.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/NatashaCSharpCompilerOptions.cs @@ -259,7 +259,7 @@ internal CSharpCompilationOptions GetCompilationOptions(OptimizationLevel optimi specificDiagnosticOptions: _reportDiagnostics, deterministic: false, concurrentBuild: true, - moduleName: Guid.NewGuid().ToString(), + moduleName: 'M'+Guid.NewGuid().ToString(), reportSuppressedDiagnostics: _suppressReportShut, metadataImportOptions: _metadataImportOptions, outputKind: _assemblyKind, diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/Utils/RuntimeInnerHelper.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/Utils/RuntimeInnerHelper.cs index 882edd7a..5ec66066 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/Utils/RuntimeInnerHelper.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Component/Compiler/Utils/RuntimeInnerHelper.cs @@ -13,7 +13,7 @@ static RuntimeInnerHelper() { AssemblyCSharpBuilder builder = new AssemblyCSharpBuilder(); var assembly = builder - .UseDefaultDomain() + .UseDefaultLoadContext() .UseSimpleMode() .WithDebugCompile(opt=>opt.WriteToAssembly()) .ConfigLoadContext(context => context diff --git a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaAssemblyBuilderExtension.cs b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaAssemblyBuilderExtension.cs index 8c2a3277..83e88cc3 100644 --- a/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaAssemblyBuilderExtension.cs +++ b/src/Natasha.CSharp/Natasha.CSharp.Compiler/Extension/NatashaAssemblyBuilderExtension.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; public static class NatashaAssemblyBuilderExtension { @@ -40,8 +41,12 @@ public static AssemblyCSharpBuilder SetCommentFilePath(this AssemblyCSharpBuilde /// /// 编译单元使用随机域 /// + /// + /// 使用 .UseRandomLoadContext 方法替代当前方法. + /// /// 编译单元 /// + [Obsolete("为了规范 API 命名,建议您使用 UseRandomLoadContext.", false)] public static AssemblyCSharpBuilder UseRandomDomain(this AssemblyCSharpBuilder builder) { builder.LoadContext = DomainManagement.Random(); @@ -49,11 +54,15 @@ public static AssemblyCSharpBuilder UseRandomDomain(this AssemblyCSharpBuilder b } /// - /// 编译单元使用新的随机域 + /// 编译单元创建指定名称的域,若同名的域已存在且未被回收,则返回已存在的域上下文. /// + /// + /// 使用 .UseNewLoadContext 方法替代当前方法. + /// /// 编译单元 /// 域名字 /// + [Obsolete("为了规范 API 命名,建议您使用 UseNewLoadContext.", false)] public static AssemblyCSharpBuilder UseNewDomain(this AssemblyCSharpBuilder builder, string domainName) { builder.LoadContext = DomainManagement.Create(domainName); @@ -61,15 +70,56 @@ public static AssemblyCSharpBuilder UseNewDomain(this AssemblyCSharpBuilder buil } /// - /// 编译单元使用新的随机域 + /// 编译单元使用默认域 /// /// 编译单元 /// + /// + /// 使用 .UseDefaultLoadContext 方法替代当前方法. + /// + [Obsolete("为了规范 API 命名,建议您使用 UseDefaultLoadContext.", false)] public static AssemblyCSharpBuilder UseDefaultDomain(this AssemblyCSharpBuilder builder) { builder.LoadContext = NatashaLoadContext.DefaultContext; return builder; } + /// + /// 编译单元使用随机域上下文 + /// + /// 编译单元 + /// + public static AssemblyCSharpBuilder UseRandomLoadContext(this AssemblyCSharpBuilder builder) + { + builder.LoadContext = DomainManagement.Random(); + return builder; + } + + /// + /// 编译单元使用名称创建新的域上下文. + /// + /// + /// (注:若 [同名的域] 未被回收,则返回已存在的域上下文.) + /// + /// 编译单元 + /// 域名字 + /// + public static AssemblyCSharpBuilder UseNewLoadContext(this AssemblyCSharpBuilder builder, string domainName) + { + builder.LoadContext = DomainManagement.Create(domainName); + return builder; + } + + /// + /// 编译单元使用默认域上下文 + /// + /// 编译单元 + /// + public static AssemblyCSharpBuilder UseDefaultLoadContext(this AssemblyCSharpBuilder builder) + { + builder.LoadContext = NatashaLoadContext.DefaultContext; + return builder; + } + }