diff --git a/GFramework.Core.Abstractions/Ioc/IIocContainer.cs b/GFramework.Core.Abstractions/Ioc/IIocContainer.cs
index 499c6e54..078b8d44 100644
--- a/GFramework.Core.Abstractions/Ioc/IIocContainer.cs
+++ b/GFramework.Core.Abstractions/Ioc/IIocContainer.cs
@@ -257,10 +257,13 @@ public interface IIocContainer : IContextAware, IDisposable
///
/// 要检查的服务类型。
/// 若存在显式注册或开放泛型映射可满足该服务类型,则返回 ;否则返回 。
+ /// 当 为 时抛出。
+ /// 当调用 时容器已被释放时抛出。
///
/// 该入口面向“先判断是否值得解析实例”的热路径优化场景。
/// 与 不同,它不会为了判断结果而激活服务实例,因此可避免把瞬态对象创建、
/// 多服务枚举或日志分配混入仅需存在性判断的调用链中。
+ /// 该方法按服务键与开放泛型映射判断可见性,不会把“仅以实现类型自身注册”的实例误判成其所有可赋值接口都已注册。
///
bool HasRegistration(Type type);
diff --git a/GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs b/GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
index 61db29ba..7f30768c 100644
--- a/GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
+++ b/GFramework.Core.Tests/Ioc/MicrosoftDiContainerTests.cs
@@ -445,6 +445,21 @@ public class MicrosoftDiContainerTests
Assert.That(_container.HasRegistration(typeof(IPipelineBehavior)), Is.True);
}
+ ///
+ /// 测试 HasRegistration 不会把仅以具体实现类型自注册的服务误判成其接口服务键也已注册。
+ ///
+ [Test]
+ public void HasRegistration_Should_ReturnFalse_For_Interface_When_Only_Concrete_Service_Key_Is_Registered()
+ {
+ _container.GetServicesUnsafe.AddSingleton(typeof(SelfRegisteredConcreteBehavior), typeof(SelfRegisteredConcreteBehavior));
+
+ Assert.That(_container.HasRegistration(typeof(IPipelineBehavior)), Is.False);
+
+ _container.Freeze();
+
+ Assert.That(_container.HasRegistration(typeof(IPipelineBehavior)), Is.False);
+ }
+
///
/// 测试当实例存在时检查实例包含关系应返回 true 的功能
///
@@ -956,4 +971,21 @@ public class MicrosoftDiContainerTests
return next(request, cancellationToken);
}
}
+
+ ///
+ /// 供 HasRegistration 服务键判定回归使用的最小封闭 pipeline 行为。
+ ///
+ private sealed class SelfRegisteredConcreteBehavior : IPipelineBehavior
+ {
+ ///
+ /// 透传到下一个 pipeline 节点,不额外改变请求语义。
+ ///
+ public ValueTask Handle(
+ HasRegistrationRequest request,
+ MessageHandlerDelegate next,
+ CancellationToken cancellationToken)
+ {
+ return next(request, cancellationToken);
+ }
+ }
}
diff --git a/GFramework.Core/Ioc/MicrosoftDiContainer.cs b/GFramework.Core/Ioc/MicrosoftDiContainer.cs
index 4a4be8d4..b9896950 100644
--- a/GFramework.Core/Ioc/MicrosoftDiContainer.cs
+++ b/GFramework.Core/Ioc/MicrosoftDiContainer.cs
@@ -1103,7 +1103,9 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null)
/// 若当前注册可用于解析 ,则返回 。
private static bool CanSatisfyServiceType(Type registeredServiceType, Type requestedType)
{
- if (registeredServiceType == requestedType || requestedType.IsAssignableFrom(registeredServiceType))
+ // 这里刻意与 Get/GetAll 的“按服务键解析”语义保持一致:
+ // 只有注册时声明的服务类型本身命中,或开放泛型服务键能闭合到请求类型时,才视为存在可见注册。
+ if (registeredServiceType == requestedType)
{
return true;
}
diff --git a/GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs b/GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs
index dde8acbe..886f2c71 100644
--- a/GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs
+++ b/GFramework.Cqrs.Benchmarks/Messaging/BenchmarkHostFactory.cs
@@ -76,14 +76,14 @@ internal static class BenchmarkHostFactory
}
///
- /// 创建承载 `ai-libs/Mediator` source-generated concrete mediator 的最小对照宿主。
+ /// 创建承载 NuGet `Mediator` source-generated concrete mediator 的最小对照宿主。
///
/// 补充当前场景的显式服务注册。
/// 可直接解析 generated `Mediator.Mediator` 的 DI 宿主。
///
/// 当前 benchmark 只把 `Mediator` 作为单例 steady-state 对照组接入,
- /// 因为它的 lifetime 由 source generator 在编译期塑形;若后续需要 `Transient` / `Scoped` 矩阵,
- /// 应按 `ai-libs/Mediator/benchmarks` 的做法拆成独立 build config,而不是在同一编译产物里混用多个 lifetime。
+ /// 因为它的 lifetime 由 source generator 在编译期塑形;若后续需要 `Transient` / `Scoped` 矩阵,
+ /// 应按 `Mediator` 官方 benchmark 的做法拆成独立 build config,而不是在同一编译产物里混用多个 lifetime。
///
internal static ServiceProvider CreateMediatorServiceProvider(Action? configure)
{
diff --git a/GFramework.Cqrs.Benchmarks/Messaging/RequestBenchmarks.cs b/GFramework.Cqrs.Benchmarks/Messaging/RequestBenchmarks.cs
index af20fcf1..37840a94 100644
--- a/GFramework.Cqrs.Benchmarks/Messaging/RequestBenchmarks.cs
+++ b/GFramework.Cqrs.Benchmarks/Messaging/RequestBenchmarks.cs
@@ -21,7 +21,7 @@ using GeneratedMediator = Mediator.Mediator;
namespace GFramework.Cqrs.Benchmarks.Messaging;
///
-/// 对比单个 request 在直接调用、GFramework.CQRS runtime、`ai-libs/Mediator` 与 MediatR 之间的 steady-state dispatch 开销。
+/// 对比单个 request 在直接调用、GFramework.CQRS runtime、NuGet `Mediator` 与 MediatR 之间的 steady-state dispatch 开销。
///
[Config(typeof(Config))]
public class RequestBenchmarks
@@ -161,6 +161,16 @@ public class RequestBenchmarks
return ValueTask.FromResult(new BenchmarkResponse(request.Id));
}
+ ///
+ /// 处理 NuGet `Mediator` request。
+ ///
+ ValueTask Mediator.IRequestHandler.Handle(
+ BenchmarkRequest request,
+ CancellationToken cancellationToken)
+ {
+ return Handle(request, cancellationToken);
+ }
+
///
/// 处理 MediatR request。
///
diff --git a/GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherContextValidationTests.cs b/GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherContextValidationTests.cs
index b2bfc153..5eec00eb 100644
--- a/GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherContextValidationTests.cs
+++ b/GFramework.Cqrs.Tests/Cqrs/CqrsDispatcherContextValidationTests.cs
@@ -30,6 +30,9 @@ internal sealed class CqrsDispatcherContextValidationTests
container
.Setup(currentContainer => currentContainer.Get(typeof(IRequestHandler)))
.Returns(new ContextAwareRequestHandler());
+ container
+ .Setup(currentContainer => currentContainer.HasRegistration(typeof(IPipelineBehavior)))
+ .Returns(false);
container
.Setup(currentContainer => currentContainer.GetAll(typeof(IPipelineBehavior)))
.Returns(Array.Empty