mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-08 17:44:29 +08:00
fix(analyzer): 收敛 CoroutineScheduler 长方法 warning
- 重构 CoroutineScheduler 的启动与完成清理阶段,降低 MA0051 并保持取消与完成语义 - 补充辅助方法注释,保留标签分组、统计和等待者唤醒顺序 - 更新 analyzer warning reduction 的恢复点与验证记录
This commit is contained in:
parent
ec0c9a7bc8
commit
f044aeb770
@ -211,58 +211,10 @@ public sealed class CoroutineScheduler(
|
||||
return default;
|
||||
}
|
||||
|
||||
if (_nextSlot >= _slots.Length)
|
||||
{
|
||||
Expand();
|
||||
}
|
||||
|
||||
var handle = new CoroutineHandle(instanceId);
|
||||
var slotIndex = _nextSlot++;
|
||||
|
||||
var slot = new CoroutineSlot
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Enumerator = coroutine,
|
||||
State = CoroutineState.Running,
|
||||
Handle = handle,
|
||||
Priority = priority
|
||||
};
|
||||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
// 取消回调可能在任意线程触发,因此这里只做排队,真正清理由 Update 主线程完成。
|
||||
slot.CancellationRegistration = cancellationToken.Register(() => _pendingKills.Enqueue(handle));
|
||||
}
|
||||
|
||||
_slots[slotIndex] = slot;
|
||||
_metadata[handle] = new CoroutineMetadata
|
||||
{
|
||||
ExecutionStage = executionStage,
|
||||
Group = group,
|
||||
Priority = priority,
|
||||
SlotIndex = slotIndex,
|
||||
StartTime = _timeSource.CurrentTime * 1000,
|
||||
State = CoroutineState.Running,
|
||||
Tag = tag
|
||||
};
|
||||
|
||||
_completionSources[handle] =
|
||||
new TaskCompletionSource<CoroutineCompletionStatus>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
_completionStatuses.Remove(handle);
|
||||
|
||||
if (!string.IsNullOrEmpty(tag))
|
||||
{
|
||||
AddTag(tag, handle);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(group))
|
||||
{
|
||||
AddGroup(group, handle);
|
||||
}
|
||||
|
||||
_statistics?.RecordStart(priority, tag);
|
||||
ActiveCoroutineCount++;
|
||||
|
||||
var slotIndex = AllocateSlotIndex();
|
||||
var slot = CreateRunningSlot(handle, coroutine, priority, cancellationToken);
|
||||
RegisterStartedCoroutine(handle, slotIndex, slot, priority, tag, group);
|
||||
Prewarm(slotIndex);
|
||||
UpdateStatisticsSnapshot();
|
||||
|
||||
@ -662,70 +614,14 @@ public sealed class CoroutineScheduler(
|
||||
CoroutineCompletionStatus completionStatus,
|
||||
Exception? exception = null)
|
||||
{
|
||||
var slot = _slots[slotIndex];
|
||||
if (slot == null)
|
||||
if (!TryGetFinalizableCoroutine(slotIndex, out var slot, out var handle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var handle = slot.Handle;
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_metadata.TryGetValue(handle, out var meta))
|
||||
{
|
||||
if (meta.State == CoroutineState.Paused && _pausedCount > 0)
|
||||
{
|
||||
_pausedCount--;
|
||||
}
|
||||
|
||||
var executionTime = _timeSource.CurrentTime * 1000 - meta.StartTime;
|
||||
switch (completionStatus)
|
||||
{
|
||||
case CoroutineCompletionStatus.Completed:
|
||||
meta.State = CoroutineState.Completed;
|
||||
_statistics?.RecordComplete(executionTime, meta.Priority, meta.Tag);
|
||||
break;
|
||||
|
||||
case CoroutineCompletionStatus.Faulted:
|
||||
meta.State = CoroutineState.Completed;
|
||||
_statistics?.RecordFailure(meta.Priority, meta.Tag);
|
||||
break;
|
||||
|
||||
case CoroutineCompletionStatus.Cancelled:
|
||||
meta.State = CoroutineState.Cancelled;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(completionStatus),
|
||||
completionStatus,
|
||||
"Unsupported coroutine completion status.");
|
||||
}
|
||||
}
|
||||
|
||||
DisposeSlotResources(slot);
|
||||
|
||||
_slots[slotIndex] = null;
|
||||
if (ActiveCoroutineCount > 0)
|
||||
{
|
||||
ActiveCoroutineCount--;
|
||||
}
|
||||
|
||||
RemoveTag(handle);
|
||||
RemoveGroup(handle);
|
||||
_metadata.Remove(handle);
|
||||
|
||||
WakeWaiters(handle);
|
||||
|
||||
if (_completionSources.Remove(handle, out var source))
|
||||
{
|
||||
source.TrySetResult(completionStatus);
|
||||
}
|
||||
|
||||
RecordCompletionStatus(handle, completionStatus);
|
||||
UpdateCompletionMetadata(handle, completionStatus);
|
||||
ReleaseCompletedCoroutine(slotIndex, slot, handle);
|
||||
CompleteCoroutineLifecycle(handle, completionStatus);
|
||||
OnCoroutineFinished?.Invoke(handle, completionStatus, exception);
|
||||
}
|
||||
|
||||
@ -799,6 +695,139 @@ public sealed class CoroutineScheduler(
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为新协程分配槽位索引,并在需要时扩容槽位数组。
|
||||
/// </summary>
|
||||
/// <returns>可写入的新槽位索引。</returns>
|
||||
private int AllocateSlotIndex()
|
||||
{
|
||||
if (_nextSlot >= _slots.Length)
|
||||
{
|
||||
Expand();
|
||||
}
|
||||
|
||||
return _nextSlot++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建处于运行态的协程槽位,并在需要时挂接跨线程取消回调。
|
||||
/// </summary>
|
||||
/// <param name="handle">新协程句柄。</param>
|
||||
/// <param name="coroutine">协程枚举器。</param>
|
||||
/// <param name="priority">协程优先级。</param>
|
||||
/// <param name="cancellationToken">外部取消令牌。</param>
|
||||
/// <returns>已初始化的协程槽位。</returns>
|
||||
private CoroutineSlot CreateRunningSlot(
|
||||
CoroutineHandle handle,
|
||||
IEnumerator<IYieldInstruction> coroutine,
|
||||
CoroutinePriority priority,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var slot = new CoroutineSlot
|
||||
{
|
||||
CancellationToken = cancellationToken,
|
||||
Enumerator = coroutine,
|
||||
State = CoroutineState.Running,
|
||||
Handle = handle,
|
||||
Priority = priority
|
||||
};
|
||||
|
||||
RegisterCancellationCallback(slot, handle, cancellationToken);
|
||||
return slot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 为支持取消的协程注册待终止排队回调。
|
||||
/// </summary>
|
||||
/// <param name="slot">目标协程槽位。</param>
|
||||
/// <param name="handle">协程句柄。</param>
|
||||
/// <param name="cancellationToken">外部取消令牌。</param>
|
||||
private void RegisterCancellationCallback(
|
||||
CoroutineSlot slot,
|
||||
CoroutineHandle handle,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (!cancellationToken.CanBeCanceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 取消回调可能在任意线程触发,因此这里只做排队,真正清理由 Update 主线程完成。
|
||||
slot.CancellationRegistration = cancellationToken.Register(() => _pendingKills.Enqueue(handle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将新协程写入调度器的槽位、元数据、标签分组和完成状态跟踪结构。
|
||||
/// </summary>
|
||||
/// <param name="handle">协程句柄。</param>
|
||||
/// <param name="slotIndex">槽位索引。</param>
|
||||
/// <param name="slot">已初始化的协程槽位。</param>
|
||||
/// <param name="priority">协程优先级。</param>
|
||||
/// <param name="tag">可选标签。</param>
|
||||
/// <param name="group">可选分组。</param>
|
||||
private void RegisterStartedCoroutine(
|
||||
CoroutineHandle handle,
|
||||
int slotIndex,
|
||||
CoroutineSlot slot,
|
||||
CoroutinePriority priority,
|
||||
string? tag,
|
||||
string? group)
|
||||
{
|
||||
_slots[slotIndex] = slot;
|
||||
_metadata[handle] = CreateCoroutineMetadata(slotIndex, priority, tag, group);
|
||||
ResetCompletionTracking(handle);
|
||||
|
||||
if (!string.IsNullOrEmpty(tag))
|
||||
{
|
||||
AddTag(tag, handle);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(group))
|
||||
{
|
||||
AddGroup(group, handle);
|
||||
}
|
||||
|
||||
_statistics?.RecordStart(priority, tag);
|
||||
ActiveCoroutineCount++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建新协程的初始元数据。
|
||||
/// </summary>
|
||||
/// <param name="slotIndex">槽位索引。</param>
|
||||
/// <param name="priority">协程优先级。</param>
|
||||
/// <param name="tag">可选标签。</param>
|
||||
/// <param name="group">可选分组。</param>
|
||||
/// <returns>与新槽位对应的元数据对象。</returns>
|
||||
private CoroutineMetadata CreateCoroutineMetadata(
|
||||
int slotIndex,
|
||||
CoroutinePriority priority,
|
||||
string? tag,
|
||||
string? group)
|
||||
{
|
||||
return new CoroutineMetadata
|
||||
{
|
||||
ExecutionStage = executionStage,
|
||||
Group = group,
|
||||
Priority = priority,
|
||||
SlotIndex = slotIndex,
|
||||
StartTime = _timeSource.CurrentTime * 1000,
|
||||
State = CoroutineState.Running,
|
||||
Tag = tag
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置协程完成跟踪,使复用句柄不会携带上一轮完成结果。
|
||||
/// </summary>
|
||||
/// <param name="handle">协程句柄。</param>
|
||||
private void ResetCompletionTracking(CoroutineHandle handle)
|
||||
{
|
||||
_completionSources[handle] =
|
||||
new TaskCompletionSource<CoroutineCompletionStatus>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
_completionStatuses.Remove(handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放单个槽位持有的资源。
|
||||
/// </summary>
|
||||
@ -824,6 +853,125 @@ public sealed class CoroutineScheduler(
|
||||
slot.Waiting = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取可被完成处理的协程槽位与句柄。
|
||||
/// 当槽位已空或句柄已失效时,说明该协程已经被其他路径清理,无需重复执行结束逻辑。
|
||||
/// </summary>
|
||||
/// <param name="slotIndex">槽位索引。</param>
|
||||
/// <param name="slot">若成功则返回槽位。</param>
|
||||
/// <param name="handle">若成功则返回句柄。</param>
|
||||
/// <returns>当存在可完成的协程时返回 <see langword="true" />。</returns>
|
||||
private bool TryGetFinalizableCoroutine(int slotIndex, out CoroutineSlot slot, out CoroutineHandle handle)
|
||||
{
|
||||
var candidate = _slots[slotIndex];
|
||||
if (candidate == null)
|
||||
{
|
||||
slot = null!;
|
||||
handle = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
handle = candidate.Handle;
|
||||
if (!handle.IsValid)
|
||||
{
|
||||
slot = null!;
|
||||
return false;
|
||||
}
|
||||
|
||||
slot = candidate;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据最终状态更新协程元数据与统计信息。
|
||||
/// </summary>
|
||||
/// <param name="handle">协程句柄。</param>
|
||||
/// <param name="completionStatus">最终结果。</param>
|
||||
private void UpdateCompletionMetadata(CoroutineHandle handle, CoroutineCompletionStatus completionStatus)
|
||||
{
|
||||
if (!_metadata.TryGetValue(handle, out var meta))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (meta.State == CoroutineState.Paused && _pausedCount > 0)
|
||||
{
|
||||
_pausedCount--;
|
||||
}
|
||||
|
||||
ApplyCompletionMetadata(meta, completionStatus);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将最终结果映射到元数据状态和统计记录。
|
||||
/// </summary>
|
||||
/// <param name="meta">协程元数据。</param>
|
||||
/// <param name="completionStatus">最终结果。</param>
|
||||
private void ApplyCompletionMetadata(CoroutineMetadata meta, CoroutineCompletionStatus completionStatus)
|
||||
{
|
||||
var executionTime = _timeSource.CurrentTime * 1000 - meta.StartTime;
|
||||
switch (completionStatus)
|
||||
{
|
||||
case CoroutineCompletionStatus.Completed:
|
||||
meta.State = CoroutineState.Completed;
|
||||
_statistics?.RecordComplete(executionTime, meta.Priority, meta.Tag);
|
||||
break;
|
||||
|
||||
case CoroutineCompletionStatus.Faulted:
|
||||
meta.State = CoroutineState.Completed;
|
||||
_statistics?.RecordFailure(meta.Priority, meta.Tag);
|
||||
break;
|
||||
|
||||
case CoroutineCompletionStatus.Cancelled:
|
||||
meta.State = CoroutineState.Cancelled;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(
|
||||
nameof(completionStatus),
|
||||
completionStatus,
|
||||
"Unsupported coroutine completion status.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放已结束协程占用的槽位和索引结构。
|
||||
/// </summary>
|
||||
/// <param name="slotIndex">槽位索引。</param>
|
||||
/// <param name="slot">已结束的协程槽位。</param>
|
||||
/// <param name="handle">协程句柄。</param>
|
||||
private void ReleaseCompletedCoroutine(int slotIndex, CoroutineSlot slot, CoroutineHandle handle)
|
||||
{
|
||||
DisposeSlotResources(slot);
|
||||
|
||||
_slots[slotIndex] = null;
|
||||
if (ActiveCoroutineCount > 0)
|
||||
{
|
||||
ActiveCoroutineCount--;
|
||||
}
|
||||
|
||||
RemoveTag(handle);
|
||||
RemoveGroup(handle);
|
||||
_metadata.Remove(handle);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 完成协程的等待者唤醒、任务结果和完成历史记录。
|
||||
/// </summary>
|
||||
/// <param name="handle">协程句柄。</param>
|
||||
/// <param name="completionStatus">最终结果。</param>
|
||||
private void CompleteCoroutineLifecycle(CoroutineHandle handle, CoroutineCompletionStatus completionStatus)
|
||||
{
|
||||
WakeWaiters(handle);
|
||||
|
||||
if (_completionSources.Remove(handle, out var source))
|
||||
{
|
||||
source.TrySetResult(completionStatus);
|
||||
}
|
||||
|
||||
RecordCompletionStatus(handle, completionStatus);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 唤醒所有等待目标协程完成的协程。
|
||||
/// </summary>
|
||||
|
||||
@ -7,21 +7,20 @@
|
||||
|
||||
## 当前恢复点
|
||||
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-006`
|
||||
- 当前阶段:`Phase 6`
|
||||
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-007`
|
||||
- 当前阶段:`Phase 7`
|
||||
- 当前焦点:
|
||||
- 已完成 `GFramework.Core/StateManagement/Store.cs` 的 `MA0051` 收口:将 `Dispatch` 拆分为“进入分发域 / 提交结果 / 退出分发域”
|
||||
三个辅助阶段,并将 reducer 快照创建拆分为精确匹配与多态匹配两条路径
|
||||
- 本轮保持 `Store` 的锁顺序、middleware 执行时机、batch 通知折叠和多态 reducer 排序规则不变,未改公共 API
|
||||
- 下一轮若继续推进,优先只处理 `GFramework.Core/Coroutine/CoroutineScheduler.cs` 的剩余 `MA0051`,不回到已完成的
|
||||
`Store` 或 `PauseStackManager`
|
||||
- 已完成 `GFramework.Core/Coroutine/CoroutineScheduler.cs` 的 `MA0051` 收口:将 `Run` 拆分为槽位分配、运行槽创建和启动注册阶段,
|
||||
将 `FinalizeCoroutine` 拆分为可完成目标读取、完成元数据更新、资源释放和生命周期收尾阶段
|
||||
- 本轮保持取消回调入队、统计记录、标签/分组清理、等待者唤醒和完成任务语义不变,未改公共 API
|
||||
- 当前 `MA0051` 主线已完成;下一轮若继续推进,应先判断剩余 `MA0048`、`MA0046`、`MA0002`、`MA0016` 是否值得继续低风险收敛
|
||||
|
||||
## 当前状态摘要
|
||||
|
||||
- 已完成 `GFramework.Core`、`GFramework.Cqrs`、`GFramework.Godot` 与部分 source generator 的低风险 warning 清理
|
||||
- 已完成多轮 CodeRabbit follow-up 修复,并用定向测试与项目/解决方案构建验证了关键回归风险
|
||||
- 当前 `PauseStackManager` 与 `Store` 的长方法 warning 已从 active 入口移除;主题内剩余 warning 主要集中在
|
||||
`GFramework.Core/Coroutine/CoroutineScheduler.cs`、文件/类型命名冲突、delegate 形状和少量公共集合抽象接口问题
|
||||
- 当前 `PauseStackManager`、`Store` 与 `CoroutineScheduler` 的长方法 warning 已从 active 入口移除;主题内剩余 warning
|
||||
主要集中在文件/类型命名冲突、delegate 形状、字符串 comparer 重载和少量公共集合抽象接口问题
|
||||
|
||||
## 当前活跃事实
|
||||
|
||||
@ -33,6 +32,8 @@
|
||||
- `RP-005` 已在不改公共 API 的前提下完成 `PauseStackManager` 两个 `MA0051` 的结构拆分,并补充销毁通知回归测试
|
||||
- `RP-006` 已在不改公共 API 的前提下完成 `Store` 两个 `MA0051` 的结构拆分,并通过定向 build/test 验证 dispatch、
|
||||
多态 reducer 匹配与历史语义未回归
|
||||
- `RP-007` 已在不改公共 API 的前提下完成 `CoroutineScheduler` 两个 `MA0051` 的结构拆分,并通过定向 build/test 验证
|
||||
调度、取消与完成状态语义未回归
|
||||
- 当前工作树分支 `fix/analyzer-warning-reduction-batch` 已在 `ai-plan/public/README.md` 建立 topic 映射
|
||||
|
||||
## 当前风险
|
||||
@ -71,11 +72,16 @@
|
||||
- 结果:`25 Warning(s)`,`0 Error(s)`;`Store.cs` 已不再出现在 `MA0051` 列表中
|
||||
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter FullyQualifiedName~StoreTests -p:RestoreFallbackFolders="" -p:RestorePackagesPath=<linux-nuget-cache> -nologo`
|
||||
- 结果:`30 Passed`,`0 Failed`
|
||||
- `RP-007` 的定向验证结果:
|
||||
- `dotnet build GFramework.Core/GFramework.Core.csproj -c Release -t:Rebuild --no-restore -p:UseSharedCompilation=false -p:TargetFramework=net8.0 -p:RestoreFallbackFolders="" -p:RestorePackagesPath=<linux-nuget-cache> -nologo -clp:"Summary;WarningsOnly"`
|
||||
- 结果:`23 Warning(s)`,`0 Error(s)`;`CoroutineScheduler.cs` 已不再出现在 `MA0051` 列表中
|
||||
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter FullyQualifiedName~CoroutineScheduler -p:RestoreFallbackFolders="" -p:RestorePackagesPath=<linux-nuget-cache> -nologo`
|
||||
- 结果:`34 Passed`,`0 Failed`
|
||||
- active 跟踪文件只保留当前恢复点、活跃事实、风险与下一步,不再重复保存已完成阶段的长篇历史
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 若要继续该主题,先读 active tracking,再按需展开历史归档中的 warning 热点与验证记录
|
||||
2. 优先在 `GFramework.Core/Coroutine/CoroutineScheduler.cs` 的 `Run` 与 `FinalizeCoroutine` 两个 `MA0051`
|
||||
中继续,保持“单文件、单 warning family”的节奏
|
||||
2. 先基于当前 `23 Warning(s)` 的唯一源位置清单,判断 `MA0048` 文件命名冲突与 `MA0046` delegate 形状是否存在低风险切入点,
|
||||
再决定是否开启下一轮 warning family 收敛
|
||||
3. 若本主题确认暂缓,可保持当前归档状态,不需要再恢复 `local-plan/`
|
||||
|
||||
@ -1,5 +1,35 @@
|
||||
# Analyzer Warning Reduction 追踪
|
||||
|
||||
## 2026-04-21 — RP-007
|
||||
|
||||
### 阶段:CoroutineScheduler `MA0051` 收口(RP-007)
|
||||
|
||||
- 依据 active tracking 中“继续只选一个 `GFramework.Core` 结构性切入点”的约束,本轮选择
|
||||
`GFramework.Core/Coroutine/CoroutineScheduler.cs`,因为剩余两个 `MA0051` 都集中在协程启动与完成清理路径,且已有
|
||||
`CoroutineSchedulerTests`、`CoroutineSchedulerAdvancedTests` 覆盖句柄创建、取消、完成状态、标签分组和等待语义
|
||||
- 将 `Run` 拆分为:
|
||||
- `AllocateSlotIndex`
|
||||
- `CreateRunningSlot`
|
||||
- `RegisterCancellationCallback`
|
||||
- `RegisterStartedCoroutine`
|
||||
- `CreateCoroutineMetadata`
|
||||
- `ResetCompletionTracking`
|
||||
- 将 `FinalizeCoroutine` 拆分为:
|
||||
- `TryGetFinalizableCoroutine`
|
||||
- `UpdateCompletionMetadata`
|
||||
- `ApplyCompletionMetadata`
|
||||
- `ReleaseCompletedCoroutine`
|
||||
- `CompleteCoroutineLifecycle`
|
||||
- 保持取消回调只做跨线程入队、`Prewarm` 时机、统计记录文本、`RemoveTag` / `RemoveGroup` / `WakeWaiters` 顺序以及
|
||||
`OnCoroutineFinished` 的同步触发时机不变,只收缩主方法长度并补齐辅助方法意图注释
|
||||
- 验证通过:
|
||||
- `dotnet build GFramework.Core/GFramework.Core.csproj -c Release -t:Rebuild --no-restore -p:UseSharedCompilation=false -p:TargetFramework=net8.0 -p:RestoreFallbackFolders="" -p:RestorePackagesPath=<linux-nuget-cache> -nologo -clp:"Summary;WarningsOnly"`
|
||||
- 结果:`23 Warning(s)`,`0 Error(s)`;`CoroutineScheduler.cs` 已不再出现在 `MA0051` 列表
|
||||
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter FullyQualifiedName~CoroutineScheduler -p:RestoreFallbackFolders="" -p:RestorePackagesPath=<linux-nuget-cache> -nologo`
|
||||
- 结果:`34 Passed`,`0 Failed`
|
||||
- 当前 `MA0051` 主线已经在本主题下完成;下一步若继续,应先重新评估剩余 `MA0048`、`MA0046`、`MA0002`、`MA0016` 的
|
||||
收敛价值与改动风险,再决定是否开启下一轮 warning family
|
||||
|
||||
## 2026-04-21 — RP-006
|
||||
|
||||
### 阶段:Store `MA0051` 收口(RP-006)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user