refactor(core): 收拢泛型家族文件以清理MA0048

- 重构 Command 与 Query 抽象基类文件布局,合并同名泛型家族到基名文件
- 迁移泛型 Event 类型到 Event.cs,保持公共 API 与行为不变
- 更新 analyzer warning reduction 的 RP-009 跟踪与验证结果
This commit is contained in:
GeWuYou 2026-04-21 12:31:24 +08:00
parent 035c7db18e
commit 33c435bad5
13 changed files with 235 additions and 222 deletions

View File

@ -1,5 +1,6 @@
using GFramework.Core.Abstractions.Command;
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
namespace GFramework.Core.Command;
@ -26,3 +27,54 @@ public abstract class AbstractAsyncCommand : ContextAwareBase, IAsyncCommand
/// <returns>表示异步操作的任务</returns>
protected abstract Task OnExecuteAsync();
}
/// <summary>
/// 抽象异步命令基类,为需要命令输入且无返回值的异步命令提供统一执行骨架。
/// </summary>
/// <typeparam name="TInput">命令输入类型,必须实现 <see cref="ICommandInput" /> 接口。</typeparam>
/// <param name="input">命令输入参数。</param>
public abstract class AbstractAsyncCommand<TInput>(TInput input) : ContextAwareBase, IAsyncCommand
where TInput : ICommandInput
{
/// <summary>
/// 执行异步命令的实现方法。
/// </summary>
/// <returns>表示异步操作的任务。</returns>
async Task IAsyncCommand.ExecuteAsync()
{
await OnExecuteAsync(input).ConfigureAwait(false);
}
/// <summary>
/// 定义异步执行逻辑的抽象方法,由派生类实现具体业务逻辑。
/// </summary>
/// <param name="input">命令输入参数。</param>
/// <returns>表示异步操作的任务。</returns>
protected abstract Task OnExecuteAsync(TInput input);
}
/// <summary>
/// 抽象异步命令基类,为需要命令输入且返回结果的异步命令提供统一执行骨架。
/// </summary>
/// <typeparam name="TInput">命令输入类型,必须实现 <see cref="ICommandInput" /> 接口。</typeparam>
/// <typeparam name="TResult">命令执行结果类型。</typeparam>
/// <param name="input">命令输入参数。</param>
public abstract class AbstractAsyncCommand<TInput, TResult>(TInput input) : ContextAwareBase, IAsyncCommand<TResult>
where TInput : ICommandInput
{
/// <summary>
/// 执行异步命令并返回结果的实现方法。
/// </summary>
/// <returns>表示异步操作且包含结果的任务。</returns>
async Task<TResult> IAsyncCommand<TResult>.ExecuteAsync()
{
return await OnExecuteAsync(input).ConfigureAwait(false);
}
/// <summary>
/// 定义异步执行逻辑的抽象方法,由派生类实现具体业务逻辑并返回结果。
/// </summary>
/// <param name="input">命令输入参数。</param>
/// <returns>表示异步操作且包含结果的任务。</returns>
protected abstract Task<TResult> OnExecuteAsync(TInput input);
}

View File

@ -1,29 +0,0 @@
using GFramework.Core.Abstractions.Command;
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
namespace GFramework.Core.Command;
/// <summary>
/// 抽象异步命令基类,用于处理无返回值的异步命令操作
/// </summary>
/// <typeparam name="TInput">命令输入类型必须实现ICommandInput接口</typeparam>
public abstract class AbstractAsyncCommand<TInput>(TInput input) : ContextAwareBase, IAsyncCommand
where TInput : ICommandInput
{
/// <summary>
/// 执行异步命令的实现方法
/// </summary>
/// <returns>表示异步操作的任务</returns>
async Task IAsyncCommand.ExecuteAsync()
{
await OnExecuteAsync(input).ConfigureAwait(false);
}
/// <summary>
/// 定义异步执行逻辑的抽象方法,由派生类实现具体业务逻辑
/// </summary>
/// <param name="input">命令输入参数</param>
/// <returns>表示异步操作的任务</returns>
protected abstract Task OnExecuteAsync(TInput input);
}

View File

@ -1,30 +0,0 @@
using GFramework.Core.Abstractions.Command;
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
namespace GFramework.Core.Command;
/// <summary>
/// 抽象异步命令基类,用于处理有返回值的异步命令操作
/// </summary>
/// <typeparam name="TInput">命令输入类型必须实现ICommandInput接口</typeparam>
/// <typeparam name="TResult">命令执行结果类型</typeparam>
public abstract class AbstractAsyncCommand<TInput, TResult>(TInput input) : ContextAwareBase, IAsyncCommand<TResult>
where TInput : ICommandInput
{
/// <summary>
/// 执行异步命令并返回结果的实现方法
/// </summary>
/// <returns>表示异步操作且包含结果的任务</returns>
async Task<TResult> IAsyncCommand<TResult>.ExecuteAsync()
{
return await OnExecuteAsync(input).ConfigureAwait(false);
}
/// <summary>
/// 定义异步执行逻辑的抽象方法,由派生类实现具体业务逻辑并返回结果
/// </summary>
/// <param name="input">命令输入参数</param>
/// <returns>表示异步操作且包含结果的任务</returns>
protected abstract Task<TResult> OnExecuteAsync(TInput input);
}

View File

@ -1,5 +1,7 @@
using GFramework.Core.Abstractions.Command;
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
using ICommand = GFramework.Core.Abstractions.Command.ICommand;
namespace GFramework.Core.Command;
@ -20,4 +22,55 @@ public abstract class AbstractCommand : ContextAwareBase, ICommand
/// 命令执行的抽象方法,由派生类实现具体的命令逻辑
/// </summary>
protected abstract void OnExecute();
}
}
/// <summary>
/// 抽象命令类,实现 <see cref="ICommand" /> 接口,为需要命令输入的具体命令提供基础架构支持。
/// </summary>
/// <typeparam name="TInput">命令输入参数类型,必须实现 <see cref="ICommandInput" /> 接口。</typeparam>
/// <param name="input">命令执行所需的输入参数。</param>
public abstract class AbstractCommand<TInput>(TInput input) : ContextAwareBase, ICommand
where TInput : ICommandInput
{
/// <summary>
/// 执行命令的入口方法,实现 <see cref="ICommand" /> 接口的 <c>Execute</c> 方法。
/// </summary>
void ICommand.Execute()
{
OnExecute(input);
}
/// <summary>
/// 命令执行的抽象方法,由派生类实现具体的命令逻辑。
/// </summary>
/// <param name="input">命令执行所需的输入参数。</param>
protected abstract void OnExecute(TInput input);
}
/// <summary>
/// 带返回值的抽象命令类,为需要输入和返回值的命令提供统一执行骨架。
/// </summary>
/// <typeparam name="TInput">命令输入参数类型,必须实现 <see cref="ICommandInput" /> 接口。</typeparam>
/// <typeparam name="TResult">命令执行后返回的结果类型。</typeparam>
/// <param name="input">命令执行所需的输入参数。</param>
public abstract class AbstractCommand<TInput, TResult>(TInput input)
: ContextAwareBase, GFramework.Core.Abstractions.Command.ICommand<TResult>
where TInput : ICommandInput
{
/// <summary>
/// 执行命令的入口方法,实现 <see cref="GFramework.Core.Abstractions.Command.ICommand{TResult}" /> 接口的
/// <c>Execute</c> 方法。
/// </summary>
/// <returns>命令执行后的结果。</returns>
TResult GFramework.Core.Abstractions.Command.ICommand<TResult>.Execute()
{
return OnExecute(input);
}
/// <summary>
/// 命令执行的抽象方法,由派生类实现具体的命令逻辑。
/// </summary>
/// <param name="input">命令执行所需的输入参数。</param>
/// <returns>命令执行后的结果。</returns>
protected abstract TResult OnExecute(TInput input);
}

View File

@ -1,28 +0,0 @@
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
using ICommand = GFramework.Core.Abstractions.Command.ICommand;
namespace GFramework.Core.Command;
/// <summary>
/// 抽象命令类,实现 ICommand 接口,为具体命令提供基础架构支持
/// </summary>
/// <typeparam name="TInput">命令输入参数类型,必须实现 ICommandInput 接口</typeparam>
/// <param name="input">命令执行所需的输入参数</param>
public abstract class AbstractCommand<TInput>(TInput input) : ContextAwareBase, ICommand
where TInput : ICommandInput
{
/// <summary>
/// 执行命令的入口方法,实现 ICommand 接口的 Execute 方法
/// </summary>
void ICommand.Execute()
{
OnExecute(input);
}
/// <summary>
/// 命令执行的抽象方法,由派生类实现具体的命令逻辑
/// </summary>
/// <param name="input">命令执行所需的输入参数</param>
protected abstract void OnExecute(TInput input);
}

View File

@ -1,31 +0,0 @@
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Command;
namespace GFramework.Core.Command;
/// <summary>
/// 带返回值的抽象命令类,实现 ICommand{TResult} 接口,为需要返回结果的命令提供基础架构支持
/// </summary>
/// <typeparam name="TInput">命令输入参数类型,必须实现 ICommandInput 接口</typeparam>
/// <typeparam name="TResult">命令执行后返回的结果类型</typeparam>
/// <param name="input">命令执行所需的输入参数</param>
public abstract class AbstractCommand<TInput, TResult>(TInput input)
: ContextAwareBase, Abstractions.Command.ICommand<TResult>
where TInput : ICommandInput
{
/// <summary>
/// 执行命令的入口方法,实现 ICommand{TResult} 接口的 Execute 方法
/// </summary>
/// <returns>命令执行后的结果</returns>
TResult Abstractions.Command.ICommand<TResult>.Execute()
{
return OnExecute(input);
}
/// <summary>
/// 命令执行的抽象方法,由派生类实现具体的命令逻辑
/// </summary>
/// <param name="input">命令执行所需的输入参数</param>
/// <returns>命令执行后的结果</returns>
protected abstract TResult OnExecute(TInput input);
}

View File

@ -3,8 +3,8 @@
namespace GFramework.Core.Events;
/// <summary>
/// 泛型事件类,支持一个泛型参数 T 的事件注册、注销与触发。
/// 实现了 IEvent 接口以提供统一的事件操作接口。
/// 泛型事件类,支持一个泛型参数 <typeparamref name="T" /> 的事件注册、注销与触发。
/// 实现了 <see cref="IEvent" /> 接口以提供统一的事件操作接口。
/// </summary>
/// <typeparam name="T">事件回调函数的第一个参数类型。</typeparam>
public class Event<T> : IEvent
@ -16,11 +16,11 @@ public class Event<T> : IEvent
private Action<T>? _mOnEvent = _ => { };
/// <summary>
/// 显式实现 IEvent 接口中的 Register 方法。
/// 允许使用无参 Action 来订阅当前带参事件。
/// 显式实现 <see cref="IEvent" /> 接口中的 <c>Register</c> 方法。
/// 允许使用无参 <see cref="Action" /> 来订阅当前带参事件。
/// </summary>
/// <param name="onEvent">无参事件处理方法。</param>
/// <returns>IUnRegister 对象,用于稍后注销该事件监听器。</returns>
/// <returns><see cref="IUnRegister" /> 对象,用于稍后注销该事件监听器。</returns>
IUnRegister IEvent.Register(Action onEvent)
{
return Register(Action);
@ -35,7 +35,7 @@ public class Event<T> : IEvent
/// 注册一个事件监听器,并返回可用于取消注册的对象。
/// </summary>
/// <param name="onEvent">要注册的事件处理方法。</param>
/// <returns>IUnRegister 对象,用于稍后注销该事件监听器。</returns>
/// <returns><see cref="IUnRegister" /> 对象,用于稍后注销该事件监听器。</returns>
public IUnRegister Register(Action<T> onEvent)
{
_mOnEvent += onEvent;
@ -52,7 +52,7 @@ public class Event<T> : IEvent
}
/// <summary>
/// 触发所有已注册的事件处理程序,并传递参数 t。
/// 触发所有已注册的事件处理程序,并传递参数 <paramref name="t" />
/// </summary>
/// <param name="t">传递给事件处理程序的参数。</param>
public void Trigger(T t)
@ -61,9 +61,9 @@ public class Event<T> : IEvent
}
/// <summary>
/// 获取当前已注册的监听器数量
/// 获取当前已注册的监听器数量
/// </summary>
/// <returns>监听器数量</returns>
/// <returns>监听器数量</returns>
public int GetListenerCount()
{
return _mOnEvent?.GetInvocationList().Length ?? 0;
@ -71,30 +71,30 @@ public class Event<T> : IEvent
}
/// <summary>
/// 支持两个泛型参数 T 和 TK 的事件类。
/// 支持两个泛型参数 <typeparamref name="T" /><typeparamref name="TK" /> 的事件类。
/// 提供事件注册、注销和触发功能。
/// </summary>
/// <typeparam name="T">第一个参数类型。</typeparam>
/// <typeparam name="Tk">第二个参数类型。</typeparam>
public class Event<T, Tk> : IEvent
/// <typeparam name="TK">第二个参数类型。</typeparam>
public class Event<T, TK> : IEvent
{
/// <summary>
/// 存储已注册的双参数事件处理委托。
/// 默认为空操作no-op委托。
/// </summary>
private Action<T, Tk>? _mOnEvent = (_, _) => { };
private Action<T, TK>? _mOnEvent = (_, _) => { };
/// <summary>
/// 显式实现 IEvent 接口中的 Register 方法。
/// 允许使用无参 Action 来订阅当前带参事件。
/// 显式实现 <see cref="IEvent" /> 接口中的 <c>Register</c> 方法。
/// 允许使用无参 <see cref="Action" /> 来订阅当前带参事件。
/// </summary>
/// <param name="onEvent">无参事件处理方法。</param>
/// <returns>IUnRegister 对象,用于稍后注销该事件监听器。</returns>
/// <returns><see cref="IUnRegister" /> 对象,用于稍后注销该事件监听器。</returns>
IUnRegister IEvent.Register(Action onEvent)
{
return Register(Action);
void Action(T _, Tk __)
void Action(T _, TK __)
{
onEvent();
}
@ -104,8 +104,8 @@ public class Event<T, Tk> : IEvent
/// 注册一个接受两个参数的事件监听器,并返回可用于取消注册的对象。
/// </summary>
/// <param name="onEvent">要注册的事件处理方法。</param>
/// <returns>IUnRegister 对象,用于稍后注销该事件监听器。</returns>
public IUnRegister Register(Action<T, Tk> onEvent)
/// <returns><see cref="IUnRegister" /> 对象,用于稍后注销该事件监听器。</returns>
public IUnRegister Register(Action<T, TK> onEvent)
{
_mOnEvent += onEvent;
return new DefaultUnRegister(() => UnRegister(onEvent));
@ -115,27 +115,27 @@ public class Event<T, Tk> : IEvent
/// 取消指定的双参数事件监听器。
/// </summary>
/// <param name="onEvent">需要被注销的事件处理方法。</param>
public void UnRegister(Action<T, Tk> onEvent)
public void UnRegister(Action<T, TK> onEvent)
{
_mOnEvent -= onEvent;
}
/// <summary>
/// 触发所有已注册的事件处理程序,并传递参数 t 和 k。
/// 触发所有已注册的事件处理程序,并传递参数 <paramref name="t" /><paramref name="k" />
/// </summary>
/// <param name="t">第一个参数。</param>
/// <param name="k">第二个参数。</param>
public void Trigger(T t, Tk k)
public void Trigger(T t, TK k)
{
_mOnEvent?.Invoke(t, k);
}
/// <summary>
/// 获取当前已注册的监听器数量
/// 获取当前已注册的监听器数量
/// </summary>
/// <returns>监听器数量</returns>
/// <returns>监听器数量</returns>
public int GetListenerCount()
{
return _mOnEvent?.GetInvocationList().Length ?? 0;
}
}
}

View File

@ -1,5 +1,6 @@
using GFramework.Core.Abstractions.Query;
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Query;
namespace GFramework.Core.Query;
@ -24,4 +25,31 @@ public abstract class AbstractAsyncQuery<TResult> : ContextAwareBase, IAsyncQuer
/// </summary>
/// <returns>返回查询结果的异步任务</returns>
protected abstract Task<TResult> OnDoAsync();
}
}
/// <summary>
/// 抽象异步查询基类,为需要输入参数的异步查询提供统一执行骨架。
/// </summary>
/// <typeparam name="TInput">查询输入类型,必须实现 <see cref="IQueryInput" /> 接口。</typeparam>
/// <typeparam name="TResult">查询结果类型。</typeparam>
/// <param name="input">查询输入参数。</param>
public abstract class AbstractAsyncQuery<TInput, TResult>(TInput input)
: ContextAwareBase, IAsyncQuery<TResult>
where TInput : IQueryInput
{
/// <summary>
/// 执行异步查询操作。
/// </summary>
/// <returns>返回查询结果的异步任务。</returns>
public Task<TResult> DoAsync()
{
return OnDoAsync(input);
}
/// <summary>
/// 抽象方法,用于实现具体的异步查询逻辑。
/// </summary>
/// <param name="input">查询输入参数。</param>
/// <returns>返回查询结果的异步任务。</returns>
protected abstract Task<TResult> OnDoAsync(TInput input);
}

View File

@ -1,33 +0,0 @@
using GFramework.Core.Abstractions.Query;
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Query;
namespace GFramework.Core.Query;
/// <summary>
/// 抽象异步查询基类用于处理输入类型为TInput、结果类型为TResult的异步查询操作
/// </summary>
/// <typeparam name="TInput">查询输入类型必须实现IQueryInput接口</typeparam>
/// <typeparam name="TResult">查询结果类型</typeparam>
/// <param name="input">查询输入参数</param>
public abstract class AbstractAsyncQuery<TInput, TResult>(
TInput input
) : ContextAwareBase, IAsyncQuery<TResult>
where TInput : IQueryInput
{
/// <summary>
/// 执行异步查询操作
/// </summary>
/// <returns>返回查询结果的异步任务</returns>
public Task<TResult> DoAsync()
{
return OnDoAsync(input);
}
/// <summary>
/// 抽象方法,用于实现具体的异步查询逻辑
/// </summary>
/// <param name="input">查询输入参数</param>
/// <returns>返回查询结果的异步任务</returns>
protected abstract Task<TResult> OnDoAsync(TInput input);
}

View File

@ -1,5 +1,6 @@
using GFramework.Core.Abstractions.Query;
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Query;
namespace GFramework.Core.Query;
@ -7,7 +8,7 @@ namespace GFramework.Core.Query;
/// 抽象查询类,提供查询操作的基础实现
/// </summary>
/// <typeparam name="TResult">查询结果的类型</typeparam>
public abstract class AbstractQuery<TResult> : ContextAwareBase, IQuery<TResult>
public abstract class AbstractQuery<TResult> : ContextAwareBase, GFramework.Core.Abstractions.Query.IQuery<TResult>
{
/// <summary>
@ -25,4 +26,31 @@ public abstract class AbstractQuery<TResult> : ContextAwareBase, IQuery<TResult>
/// </summary>
/// <returns>查询结果类型为TResult</returns>
protected abstract TResult OnDo();
}
}
/// <summary>
/// 抽象查询类,为需要输入参数的同步查询提供基础实现。
/// </summary>
/// <typeparam name="TInput">查询输入参数的类型,必须实现 <see cref="IQueryInput" /> 接口。</typeparam>
/// <typeparam name="TResult">查询结果的类型。</typeparam>
/// <param name="input">查询输入参数。</param>
public abstract class AbstractQuery<TInput, TResult>(TInput input)
: ContextAwareBase, GFramework.Core.Abstractions.Query.IQuery<TResult>
where TInput : IQueryInput
{
/// <summary>
/// 执行查询操作。
/// </summary>
/// <returns>查询结果,类型为 <typeparamref name="TResult" />。</returns>
public TResult Do()
{
return OnDo(input);
}
/// <summary>
/// 抽象方法,用于实现具体的查询逻辑。
/// </summary>
/// <param name="input">查询输入参数。</param>
/// <returns>查询结果。</returns>
protected abstract TResult OnDo(TInput input);
}

View File

@ -1,30 +0,0 @@
using GFramework.Core.Rule;
using GFramework.Cqrs.Abstractions.Cqrs.Query;
namespace GFramework.Core.Query;
/// <summary>
/// 抽象查询类,提供查询操作的基础实现
/// </summary>
/// <typeparam name="TInput">查询输入参数的类型必须实现IQueryInput接口</typeparam>
/// <typeparam name="TResult">查询结果的类型</typeparam>
public abstract class AbstractQuery<TInput, TResult>(TInput input)
: ContextAwareBase, Abstractions.Query.IQuery<TResult>
where TInput : IQueryInput
{
/// <summary>
/// 执行查询操作
/// </summary>
/// <returns>查询结果类型为TResult</returns>
public TResult Do()
{
return OnDo(input);
}
/// <summary>
/// 抽象方法,用于实现具体的查询逻辑
/// </summary>
/// <param name="input">查询输入参数</param>
/// <returns>查询结果类型为TResult</returns>
protected abstract TResult OnDo(TInput input);
}

View File

@ -7,12 +7,13 @@
## 当前恢复点
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-008`
- 当前阶段:`Phase 8`
- 恢复点编号:`ANALYZER-WARNING-REDUCTION-RP-009`
- 当前阶段:`Phase 9`
- 当前焦点:
- 当前 `MA0051` 主线已完成;后续改为按 warning 类型和数量批处理,而不是继续按单文件切片推进
- 优先批量收敛当前数量最高且风险较低的类型;当某一轮主类型数量不足时,允许顺手合并其他低冲突 warning 类型,
`MA0015``MA0077` 只是当前最明显的低数量示例,不构成限定
- 当前 `MA0048` 已在 `GFramework.Core``net8.0` warnings-only 基线中清零;下一轮切到 `MA0046`
- 后续继续按 warning 类型和数量批处理,而不是回退到按单文件切片推进
- 当某一轮主类型数量不足时,允许顺手合并其他低冲突 warning 类型,`MA0015``MA0077`
只是当前最明显的低数量示例,不构成限定
- 单次 `boot` 的工作树改动上限控制在约 `100` 个文件以内,避免 recovery context 与 review 面同时失控
- 若任务边界互不冲突,允许使用不同模型的 subagent 并行处理不同 warning 类型或不同目录,但必须遵守显式 ownership
@ -20,9 +21,9 @@
- 已完成 `GFramework.Core``GFramework.Cqrs``GFramework.Godot` 与部分 source generator 的低风险 warning 清理
- 已完成多轮 CodeRabbit follow-up 修复,并用定向测试与项目/解决方案构建验证了关键回归风险
- 当前 `PauseStackManager``Store``CoroutineScheduler` 的长方法 warning 已从 active 入口移除;主题内剩余 warning
主要集中在 `MA0048` 文件/类型命名冲突、`MA0046` delegate 形状、`MA0016` 集合抽象接口、`MA0002` comparer 重载,
以及 `MA0015` / `MA0077` 两个低数量尾项
- 当前 `PauseStackManager``Store``CoroutineScheduler``GFramework.Core``MA0048`
文件/类型命名冲突已从 active 入口移除;主题内剩余 warning 主要集中在 `MA0046` delegate 形状、
`MA0016` 集合抽象接口、`MA0002` comparer 重载,以及 `MA0015` / `MA0077` 两个低数量尾项
## 当前活跃事实
@ -38,12 +39,14 @@
调度、取消与完成状态语义未回归
- `RP-008` 将后续策略从“单文件 warning 切片”切换为“按类型批处理 + 文件数上限控制”,并允许在非冲突前提下使用
不同模型的 subagent 并行处理
- `RP-009` 在不改公共 API 的前提下,将同名泛型家族收拢到与类型名一致的单文件中,清空当前 `GFramework.Core`
`net8.0` 基线中的 `MA0048`,并通过定向 build/test 验证 `Command``Query``Event` 路径未回归
- 当前工作树分支 `fix/analyzer-warning-reduction-batch` 已在 `ai-plan/public/README.md` 建立 topic 映射
## 当前风险
- 结构性重构风险:剩余 `GFramework.Core``MA0051``MA0048` 可能要求较大的文件拆分或类型重命名
- 缓解措施:按 warning 类型分批推进,并把单次 `boot` 的文件改动规模控制在约 `100` 个文件以内
- 公共契约兼容风险:剩余 `MA0046` / `MA0016` 若直接改公开委托或集合类型,可能波及用户代码
- 缓解措施:优先选择不改公共 API 的低风险切法;若必须触达公共契约,先补齐 XML 契约说明与定向测试
- 测试宿主稳定性风险:部分 Godot 失败路径在当前 .NET 测试宿主下仍不稳定
- 缓解措施:继续优先使用稳定的 targeted test、项目构建和相邻 smoke test 组合验证
- 多目标框架 warning 解释风险:同一源位置会在多个 target framework 下重复计数
@ -86,11 +89,16 @@
- `RP-008` 的策略基线:
- 当前 `GFramework.Core` 剩余 warning 分布:`MA0048=8``MA0046=6``MA0016=5``MA0002=2``MA0015=1``MA0077=1`
- 后续批处理规则:优先按类型推进;若当轮主类型数量不足,可顺手吸收其他低冲突类型,不限定于 `MA0015``MA0077`
- `RP-009` 的定向验证结果:
- `dotnet build GFramework.Core/GFramework.Core.csproj -c Release -t:Rebuild --no-restore -p:UseSharedCompilation=false -p:TargetFramework=net8.0 -p:RestoreFallbackFolders="" -nologo -clp:"Summary;WarningsOnly"`
- 结果:`15 Warning(s)``0 Error(s)`;当前 `GFramework.Core` `net8.0` warnings-only 输出中已不再出现 `MA0048`
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~CommandExecutorTests|FullyQualifiedName~AbstractAsyncCommandTests|FullyQualifiedName~QueryExecutorTests|FullyQualifiedName~AbstractAsyncQueryTests|FullyQualifiedName~EventTests" -m:1 -p:RestoreFallbackFolders="" -nologo`
- 结果:`83 Passed``0 Failed`
- active 跟踪文件只保留当前恢复点、活跃事实、风险与下一步,不再重复保存已完成阶段的长篇历史
## 下一步
1. 若要继续该主题,先读 active tracking再按需展开历史归档中的 warning 热点与验证记录
2. 下一轮优先以 `MA0048` 为主批次启动;若改动规模和风险允许,可顺手并入其他低冲突类型,而不限定于单独的尾项 warning
3. 若 `MA0048` 的文件 ownership 可以清晰切分,允许使用不同模型的 subagent 并行处理互不冲突的目录或类型簇
2. 下一轮优先以 `MA0046` 为主批次启动,先从 `Architecture*``CoroutineScheduler` 的低风险 delegate 形状修正中选一个切入点
3. 若 `MA0046` 的文件 ownership 可以清晰切分,允许使用不同模型的 subagent 并行处理互不冲突的目录或类型簇
4. 若本主题确认暂缓,可保持当前归档状态,不需要再恢复 `local-plan/`

View File

@ -1,5 +1,30 @@
# Analyzer Warning Reduction 追踪
## 2026-04-21 — RP-009
### 阶段:`MA0048` 批次收口RP-009
- 依据 `RP-008` 的批处理策略,本轮继续从 `GFramework.Core``MA0048` 启动,但不采用重命名公共类型的高风险做法;
改为把同名不同泛型 arity 的家族收拢到与类型名一致的单文件中
- 具体调整:
- 将 `AbstractCommand<TInput>``AbstractCommand<TInput, TResult>` 合并进 `AbstractCommand.cs`
- 将 `AbstractAsyncCommand<TInput>``AbstractAsyncCommand<TInput, TResult>` 合并进 `AbstractAsyncCommand.cs`
- 将 `AbstractQuery<TInput, TResult>` 合并进 `AbstractQuery.cs`
- 将 `AbstractAsyncQuery<TInput, TResult>` 合并进 `AbstractAsyncQuery.cs`
- 将泛型 `Event<T>` / `Event<T, TK>``EasyEventGeneric.cs` 迁移到 `Event.cs`
- 首次构建暴露出合并后的 `ICommand<TResult>` / `IQuery<TResult>` 命名空间歧义;随后改用
`GFramework.Core.Abstractions.*` 的限定名完成最小修正,没有引入行为改动
- 定向验证通过:
- `dotnet build GFramework.Core/GFramework.Core.csproj -c Release -t:Rebuild --no-restore -p:UseSharedCompilation=false -p:TargetFramework=net8.0 -p:RestoreFallbackFolders="" -nologo -clp:"Summary;WarningsOnly"`
- 结果:`15 Warning(s)``0 Error(s)``MA0048` 已从当前 `GFramework.Core` `net8.0` warnings-only 基线中清空
- `dotnet test GFramework.Core.Tests/GFramework.Core.Tests.csproj -c Release --filter "FullyQualifiedName~CommandExecutorTests|FullyQualifiedName~AbstractAsyncCommandTests|FullyQualifiedName~QueryExecutorTests|FullyQualifiedName~AbstractAsyncQueryTests|FullyQualifiedName~EventTests" -m:1 -p:RestoreFallbackFolders="" -nologo`
- 结果:`83 Passed``0 Failed`
- 当前建议的下一批次顺序更新为:
- 第一优先级:`MA0046`
- 第二优先级:`MA0016`
- 顺手吸收:`MA0015``MA0077`
- 单独评估:`MA0002`
## 2026-04-21 — RP-008
### 阶段批处理策略切换RP-008