diff --git a/CLAUDE.md b/CLAUDE.md index 1962098f..e2e656c3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -74,7 +74,8 @@ Architecture 负责统一生命周期编排,核心阶段包括: ### CQRS 命令与查询分离,支持同步与异步执行。当前版本内建自有 CQRS runtime、行为管道和 handler 自动注册;公开 API 里仍保留少量历史 -`Mediator` 命名以兼容旧调用点。 +`Mediator` 命名以兼容旧调用点,但这些别名已进入正式弃用周期:新代码应使用 `Cqrs` 命名入口,旧别名会继续兼容一段时间并计划在未来 +major 版本中移除。 ### EventBus diff --git a/GFramework.Core.Abstractions/Architectures/IArchitecture.cs b/GFramework.Core.Abstractions/Architectures/IArchitecture.cs index b344717d..16386d5a 100644 --- a/GFramework.Core.Abstractions/Architectures/IArchitecture.cs +++ b/GFramework.Core.Abstractions/Architectures/IArchitecture.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using GFramework.Core.Abstractions.Lifecycle; using GFramework.Core.Abstractions.Model; using GFramework.Core.Abstractions.Systems; @@ -84,11 +85,14 @@ public interface IArchitecture : IAsyncInitializable, IAsyncDestroyable, IInitia /// /// 注册 CQRS 请求管道行为。 /// 该成员保留旧名称以兼容历史调用点,内部行为与 一致。 + /// 新代码不应继续依赖该别名;兼容层计划在未来的 major 版本中移除。 /// 既支持实现 IPipelineBehavior<,> 的开放泛型行为类型, /// 也支持绑定到单一请求/响应对的封闭行为类型。 /// /// 行为类型,必须是引用类型 - [Obsolete("Use RegisterCqrsPipelineBehavior() instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete( + "Use RegisterCqrsPipelineBehavior() instead. This compatibility alias will be removed in a future major version.")] void RegisterMediatorBehavior() where TBehavior : class; diff --git a/GFramework.Core.Abstractions/Ioc/IIocContainer.cs b/GFramework.Core.Abstractions/Ioc/IIocContainer.cs index c56b71fa..aead5a9d 100644 --- a/GFramework.Core.Abstractions/Ioc/IIocContainer.cs +++ b/GFramework.Core.Abstractions/Ioc/IIocContainer.cs @@ -1,4 +1,5 @@ -using GFramework.Core.Abstractions.Rule; +using System.ComponentModel; +using GFramework.Core.Abstractions.Rule; using GFramework.Core.Abstractions.Systems; using Microsoft.Extensions.DependencyInjection; @@ -99,9 +100,12 @@ public interface IIocContainer : IContextAware /// /// 注册 CQRS 请求管道行为。 /// 该成员保留旧名称以兼容历史调用点,内部行为与 一致。 + /// 新代码不应继续依赖该别名;兼容层计划在未来的 major 版本中移除。 /// /// 行为类型,必须是引用类型 - [Obsolete("Use RegisterCqrsPipelineBehavior() instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete( + "Use RegisterCqrsPipelineBehavior() instead. This compatibility alias will be removed in a future major version.")] void RegisterMediatorBehavior() where TBehavior : class; diff --git a/GFramework.Core.Tests/Cqrs/MediatorCompatibilityDeprecationTests.cs b/GFramework.Core.Tests/Cqrs/MediatorCompatibilityDeprecationTests.cs new file mode 100644 index 00000000..2e3bdbca --- /dev/null +++ b/GFramework.Core.Tests/Cqrs/MediatorCompatibilityDeprecationTests.cs @@ -0,0 +1,99 @@ +using System.ComponentModel; +using System.Reflection; +using GFramework.Core.Abstractions.Architectures; +using GFramework.Core.Abstractions.Ioc; +using GFramework.Core.Architectures; +using GFramework.Core.Coroutine.Extensions; +using GFramework.Core.Ioc; + +namespace GFramework.Core.Tests.Cqrs; + +/// +/// 锁定历史 Mediator 兼容入口的正式弃用策略。 +/// 这些测试确保旧 API 不仅保留行为兼容,还会通过编译期提示和 IntelliSense 隐藏引导调用方迁移到新的 CQRS 命名。 +/// +[TestFixture] +public class MediatorCompatibilityDeprecationTests +{ + /// + /// 验证公开兼容方法仍可用,但已被显式标记为未来移除的旧别名。 + /// + [Test] + public void Legacy_Public_Methods_Should_Be_Obsolete_And_Hidden_From_Editor_Browsing() + { + AssertLegacyMethod(typeof(IArchitecture), nameof(IArchitecture.RegisterMediatorBehavior)); + AssertLegacyMethod(typeof(IIocContainer), nameof(IIocContainer.RegisterMediatorBehavior)); + AssertLegacyMethod(typeof(Architecture), nameof(Architecture.RegisterMediatorBehavior)); + AssertLegacyMethod(typeof(MicrosoftDiContainer), nameof(MicrosoftDiContainer.RegisterMediatorBehavior)); + } + + /// + /// 验证历史扩展类型会把迁移目标写入弃用说明,并从 IntelliSense 主路径隐藏。 + /// + [Test] + public void Legacy_Extension_Types_Should_Be_Obsolete_And_Hidden_From_Editor_Browsing() + { + AssertLegacyType( + typeof(ContextAwareMediatorExtensions), + "Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsExtensions instead."); + AssertLegacyType( + typeof(ContextAwareMediatorCommandExtensions), + "Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsCommandExtensions instead."); + AssertLegacyType( + typeof(ContextAwareMediatorQueryExtensions), + "Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsQueryExtensions instead."); + AssertLegacyType( + typeof(MediatorCoroutineExtensions), + "Use GFramework.Core.Cqrs.Extensions.CqrsCoroutineExtensions instead."); + } + + /// + /// 断言方法级兼容 API 具备统一的弃用元数据。 + /// + /// 声明该方法的类型。 + /// 方法名称。 + private static void AssertLegacyMethod(Type declaringType, string methodName) + { + var method = declaringType + .GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Single(candidate => candidate.Name == methodName); + + var obsoleteAttribute = method.GetCustomAttribute(); + var editorBrowsableAttribute = method.GetCustomAttribute(); + + Assert.Multiple(() => + { + Assert.That(obsoleteAttribute, Is.Not.Null); + Assert.That( + obsoleteAttribute!.Message, + Does.Contain("Use RegisterCqrsPipelineBehavior() instead.")); + Assert.That( + obsoleteAttribute.Message, + Does.Contain("removed in a future major version")); + Assert.That(editorBrowsableAttribute, Is.Not.Null); + Assert.That(editorBrowsableAttribute!.State, Is.EqualTo(EditorBrowsableState.Never)); + }); + } + + /// + /// 断言类型级兼容扩展具备统一的弃用元数据。 + /// + /// 兼容扩展类型。 + /// 期望的迁移提示。 + private static void AssertLegacyType(Type type, string expectedReplacementHint) + { + var obsoleteAttribute = type.GetCustomAttribute(); + var editorBrowsableAttribute = type.GetCustomAttribute(); + + Assert.Multiple(() => + { + Assert.That(obsoleteAttribute, Is.Not.Null); + Assert.That(obsoleteAttribute!.Message, Does.Contain(expectedReplacementHint)); + Assert.That( + obsoleteAttribute.Message, + Does.Contain("removed in a future major version")); + Assert.That(editorBrowsableAttribute, Is.Not.Null); + Assert.That(editorBrowsableAttribute!.State, Is.EqualTo(EditorBrowsableState.Never)); + }); + } +} diff --git a/GFramework.Core/Architectures/Architecture.cs b/GFramework.Core/Architectures/Architecture.cs index ec571ee8..0395347d 100644 --- a/GFramework.Core/Architectures/Architecture.cs +++ b/GFramework.Core/Architectures/Architecture.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using GFramework.Core.Abstractions.Architectures; using GFramework.Core.Abstractions.Enums; using GFramework.Core.Abstractions.Environment; @@ -157,9 +158,12 @@ public abstract class Architecture : IArchitecture /// /// 注册 CQRS 请求管道行为。 /// 该成员保留旧名称以兼容历史调用点,内部行为与 一致。 + /// 新代码不应继续依赖该别名;兼容层计划在未来的 major 版本中移除。 /// /// 行为类型,必须是引用类型 - [Obsolete("Use RegisterCqrsPipelineBehavior() instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete( + "Use RegisterCqrsPipelineBehavior() instead. This compatibility alias will be removed in a future major version.")] public void RegisterMediatorBehavior() where TBehavior : class { RegisterCqrsPipelineBehavior(); diff --git a/GFramework.Core/Architectures/ArchitectureModules.cs b/GFramework.Core/Architectures/ArchitectureModules.cs index 7563e276..a0c1b149 100644 --- a/GFramework.Core/Architectures/ArchitectureModules.cs +++ b/GFramework.Core/Architectures/ArchitectureModules.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using GFramework.Core.Abstractions.Architectures; using GFramework.Core.Abstractions.Logging; @@ -26,9 +27,12 @@ internal sealed class ArchitectureModules( /// /// 注册 CQRS 请求管道行为。 /// 该成员保留旧名称以兼容历史调用点,内部行为与 一致。 + /// 新代码不应继续依赖该别名;兼容层计划在未来的 major 版本中移除。 /// /// 行为类型,必须是引用类型 - [Obsolete("Use RegisterCqrsPipelineBehavior() instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete( + "Use RegisterCqrsPipelineBehavior() instead. This compatibility alias will be removed in a future major version.")] public void RegisterMediatorBehavior() where TBehavior : class { RegisterCqrsPipelineBehavior(); diff --git a/GFramework.Core/Coroutine/Extensions/MediatorCoroutineExtensions.cs b/GFramework.Core/Coroutine/Extensions/MediatorCoroutineExtensions.cs index 91ed0238..f955f175 100644 --- a/GFramework.Core/Coroutine/Extensions/MediatorCoroutineExtensions.cs +++ b/GFramework.Core/Coroutine/Extensions/MediatorCoroutineExtensions.cs @@ -11,6 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +using System.ComponentModel; using GFramework.Core.Abstractions.Coroutine; using GFramework.Core.Abstractions.Cqrs; using GFramework.Core.Abstractions.Rule; @@ -21,8 +22,11 @@ namespace GFramework.Core.Coroutine.Extensions; /// /// 提供 CQRS 命令与协程集成的扩展方法。 /// 该类型保留旧名称以兼容历史调用点;新代码应改用 。 +/// 兼容层计划在未来的 major 版本中移除,因此不会继续承载新能力。 /// -[Obsolete("Use GFramework.Core.Cqrs.Extensions.CqrsCoroutineExtensions instead.")] +[EditorBrowsable(EditorBrowsableState.Never)] +[Obsolete( + "Use GFramework.Core.Cqrs.Extensions.CqrsCoroutineExtensions instead. This compatibility alias will be removed in a future major version.")] public static class MediatorCoroutineExtensions { /// diff --git a/GFramework.Core/Extensions/ContextAwareMediatorCommandExtensions.cs b/GFramework.Core/Extensions/ContextAwareMediatorCommandExtensions.cs index 9fc9311b..85f9776e 100644 --- a/GFramework.Core/Extensions/ContextAwareMediatorCommandExtensions.cs +++ b/GFramework.Core/Extensions/ContextAwareMediatorCommandExtensions.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using GFramework.Core.Abstractions.Cqrs.Command; using GFramework.Core.Abstractions.Rule; using GFramework.Core.Cqrs.Extensions; @@ -7,8 +8,11 @@ namespace GFramework.Core.Extensions; /// /// 提供对 接口的 CQRS 命令扩展方法。 /// 该类型保留旧名称以兼容历史调用点;新代码应改用 。 +/// 兼容层计划在未来的 major 版本中移除,因此不会继续承载新能力。 /// -[Obsolete("Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsCommandExtensions instead.")] +[EditorBrowsable(EditorBrowsableState.Never)] +[Obsolete( + "Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsCommandExtensions instead. This compatibility alias will be removed in a future major version.")] public static class ContextAwareMediatorCommandExtensions { /// diff --git a/GFramework.Core/Extensions/ContextAwareMediatorExtensions.cs b/GFramework.Core/Extensions/ContextAwareMediatorExtensions.cs index 4b63e223..68b130ce 100644 --- a/GFramework.Core/Extensions/ContextAwareMediatorExtensions.cs +++ b/GFramework.Core/Extensions/ContextAwareMediatorExtensions.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using GFramework.Core.Abstractions.Cqrs; using GFramework.Core.Abstractions.Rule; using GFramework.Core.Cqrs.Extensions; @@ -7,8 +8,11 @@ namespace GFramework.Core.Extensions; /// /// 提供对 接口的 CQRS 统一接口扩展方法。 /// 该类型保留旧名称以兼容历史调用点;新代码应改用 。 +/// 兼容层计划在未来的 major 版本中移除,因此不会继续承载新能力。 /// -[Obsolete("Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsExtensions instead.")] +[EditorBrowsable(EditorBrowsableState.Never)] +[Obsolete( + "Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsExtensions instead. This compatibility alias will be removed in a future major version.")] public static class ContextAwareMediatorExtensions { /// diff --git a/GFramework.Core/Extensions/ContextAwareMediatorQueryExtensions.cs b/GFramework.Core/Extensions/ContextAwareMediatorQueryExtensions.cs index be2d70e1..d7fada4a 100644 --- a/GFramework.Core/Extensions/ContextAwareMediatorQueryExtensions.cs +++ b/GFramework.Core/Extensions/ContextAwareMediatorQueryExtensions.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using GFramework.Core.Abstractions.Cqrs.Query; using GFramework.Core.Abstractions.Rule; using GFramework.Core.Cqrs.Extensions; @@ -7,8 +8,11 @@ namespace GFramework.Core.Extensions; /// /// 提供对 接口的 CQRS 查询扩展方法。 /// 该类型保留旧名称以兼容历史调用点;新代码应改用 。 +/// 兼容层计划在未来的 major 版本中移除,因此不会继续承载新能力。 /// -[Obsolete("Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsQueryExtensions instead.")] +[EditorBrowsable(EditorBrowsableState.Never)] +[Obsolete( + "Use GFramework.Core.Cqrs.Extensions.ContextAwareCqrsQueryExtensions instead. This compatibility alias will be removed in a future major version.")] public static class ContextAwareMediatorQueryExtensions { /// diff --git a/GFramework.Core/Ioc/MicrosoftDiContainer.cs b/GFramework.Core/Ioc/MicrosoftDiContainer.cs index 69b46720..3b0396c1 100644 --- a/GFramework.Core/Ioc/MicrosoftDiContainer.cs +++ b/GFramework.Core/Ioc/MicrosoftDiContainer.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using GFramework.Core.Abstractions.Bases; using GFramework.Core.Abstractions.Cqrs; using GFramework.Core.Abstractions.Ioc; @@ -360,9 +361,12 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) /// /// 注册 CQRS 请求管道行为。 /// 该成员保留旧名称以兼容历史调用点,内部行为与 一致。 + /// 新代码不应继续依赖该别名;兼容层计划在未来的 major 版本中移除。 /// /// 行为类型,必须是引用类型 - [Obsolete("Use RegisterCqrsPipelineBehavior() instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete( + "Use RegisterCqrsPipelineBehavior() instead. This compatibility alias will be removed in a future major version.")] public void RegisterMediatorBehavior() where TBehavior : class { RegisterCqrsPipelineBehavior(); diff --git a/docs/zh-CN/core/cqrs.md b/docs/zh-CN/core/cqrs.md index 3effaa86..a38fbdfa 100644 --- a/docs/zh-CN/core/cqrs.md +++ b/docs/zh-CN/core/cqrs.md @@ -223,7 +223,8 @@ public class GameArchitecture : Architecture 如果处理器位于其他模块或扩展程序集中,需要额外接入对应程序集的处理器注册,而不是依赖默认扫描。 `RegisterCqrsPipelineBehavior()` 是推荐入口;旧的 `RegisterMediatorBehavior()` -仅作为兼容名称保留。当前接口支持两种形式: +仅作为兼容名称保留,当前已标记为 `Obsolete` 并从 IntelliSense 主路径隐藏,计划在未来 major 版本中移除。 +`ContextAwareMediator*Extensions` 与 `MediatorCoroutineExtensions` 也遵循同样的弃用节奏。当前接口支持两种形式: - 开放泛型行为,例如 `LoggingBehavior<,>`,用于匹配所有请求 - 封闭行为类型,例如某个只服务于单一请求的 `SpecialBehavior`