diff --git a/GFramework.Core.Abstractions/events/EventContext.cs b/GFramework.Core.Abstractions/events/EventContext.cs new file mode 100644 index 0000000..6d4e736 --- /dev/null +++ b/GFramework.Core.Abstractions/events/EventContext.cs @@ -0,0 +1,26 @@ +namespace GFramework.Core.Abstractions.events; + +/// +/// 事件上下文,包装事件数据并提供控制方法 +/// +/// 事件数据类型 +public class EventContext(T data) +{ + /// + /// 事件数据 + /// + public T Data { get; } = data; + + /// + /// 事件是否已被处理 + /// + public bool IsHandled { get; private set; } + + /// + /// 标记事件为已处理,停止后续传播(仅对 UntilHandled 模式有效) + /// + public void MarkAsHandled() + { + IsHandled = true; + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/events/EventBusPriorityTests.cs b/GFramework.Core.Tests/events/EventBusPriorityTests.cs index 9a8a832..2f6d013 100644 --- a/GFramework.Core.Tests/events/EventBusPriorityTests.cs +++ b/GFramework.Core.Tests/events/EventBusPriorityTests.cs @@ -234,4 +234,127 @@ public class EventBusPriorityTests // Assert Assert.That(executionOrder, Is.EqualTo(new[] { "first", "second", "third" })); } -} + + [Test] + public void UntilHandled_Should_Stop_After_MarkAsHandled() + { + // Arrange + var eventBus = new EventBus(); + var executionOrder = new List(); + + eventBus.RegisterWithContext(ctx => + { + executionOrder.Add(1); + ctx.MarkAsHandled(); + }, priority: 10); + + eventBus.RegisterWithContext(ctx => + { + executionOrder.Add(2); // 不应该执行 + }, priority: 5); + + // Act + eventBus.Send(new TestEvent(), EventPropagation.UntilHandled); + + // Assert + Assert.That(executionOrder, Is.EqualTo(new[] { 1 })); + } + + [Test] + public void UntilHandled_Should_Execute_All_If_Not_Handled() + { + // Arrange + var eventBus = new EventBus(); + var executionOrder = new List(); + + eventBus.RegisterWithContext(ctx => executionOrder.Add(1), priority: 10); + eventBus.RegisterWithContext(ctx => executionOrder.Add(2), priority: 5); + + // Act + eventBus.Send(new TestEvent(), EventPropagation.UntilHandled); + + // Assert + Assert.That(executionOrder, Is.EqualTo(new[] { 1, 2 })); + } + + [Test] + public void RegisterWithContext_Should_Receive_Event_Data() + { + // Arrange + var eventBus = new EventBus(); + string? receivedMessage = null; + + eventBus.RegisterWithContext(ctx => { receivedMessage = ctx.Data.Message; }); + + // Act + eventBus.Send(new TestEvent { Message = "Hello" }, EventPropagation.All); + + // Assert + Assert.That(receivedMessage, Is.EqualTo("Hello")); + } + + [Test] + public void UntilHandled_Should_Respect_Priority_Order() + { + // Arrange + var eventBus = new EventBus(); + var executionOrder = new List(); + + eventBus.RegisterWithContext(ctx => executionOrder.Add(1), priority: 1); + eventBus.RegisterWithContext(ctx => + { + executionOrder.Add(3); + ctx.MarkAsHandled(); + }, priority: 3); + eventBus.RegisterWithContext(ctx => executionOrder.Add(2), priority: 2); + + // Act + eventBus.Send(new TestEvent(), EventPropagation.UntilHandled); + + // Assert + Assert.That(executionOrder, Is.EqualTo(new[] { 3 })); + } + + [Test] + public void Handler_Can_Unregister_Itself_Without_Exception() + { + // Arrange + var eventBus = new EventBus(); + var executionCount = 0; + IUnRegister? unregister = null; + + unregister = eventBus.Register(_ => + { + executionCount++; + unregister?.UnRegister(); + }, priority: 1); + + // Act & Assert + Assert.DoesNotThrow(() => eventBus.Send(new TestEvent(), EventPropagation.All)); + Assert.That(executionCount, Is.EqualTo(1)); + + // 第二次触发不应执行 + eventBus.Send(new TestEvent(), EventPropagation.All); + Assert.That(executionCount, Is.EqualTo(1)); + } + + [Test] + public void Concurrent_Trigger_And_Register_Should_Be_Thread_Safe() + { + // Arrange + var eventBus = new EventBus(); + var counter = 0; + eventBus.Register(_ => Interlocked.Increment(ref counter), priority: 1); + + // Act + var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() => + { + eventBus.Send(new TestEvent(), EventPropagation.All); + eventBus.Register(_ => { }, priority: 1); + })).ToArray(); + + // Assert + Assert.DoesNotThrow(() => Task.WaitAll(tasks)); + Assert.That(counter, Is.GreaterThan(0)); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/events/PriorityEventTests.cs b/GFramework.Core.Tests/events/PriorityEventTests.cs new file mode 100644 index 0000000..dfd3f97 --- /dev/null +++ b/GFramework.Core.Tests/events/PriorityEventTests.cs @@ -0,0 +1,165 @@ +using GFramework.Core.Abstractions.events; +using GFramework.Core.events; +using NUnit.Framework; + +namespace GFramework.Core.Tests.events; + +/// +/// 测试 PriorityEvent 的线程安全性和边界情况 +/// +[TestFixture] +public class PriorityEventTests +{ + [Test] + public void Trigger_Should_Not_Throw_When_Handler_Unregisters_Itself() + { + // Arrange + var evt = new PriorityEvent(); + IUnRegister? unregister = null; + + unregister = evt.Register(x => { unregister?.UnRegister(); }); + + // Act & Assert + Assert.DoesNotThrow(() => evt.Trigger(42)); + } + + [Test] + public void Trigger_Should_Be_Thread_Safe() + { + // Arrange + var evt = new PriorityEvent(); + var counter = 0; + evt.Register(x => Interlocked.Increment(ref counter)); + + // Act + var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() => + { + evt.Trigger(1); + evt.Register(x => { }); + })).ToArray(); + + // Assert + Assert.DoesNotThrow(() => Task.WaitAll(tasks)); + } + + [Test] + public void Multiple_Handlers_Unregistering_During_Trigger_Should_Not_Throw() + { + // Arrange + var evt = new PriorityEvent(); + var unregisters = new List(); + + for (int i = 0; i < 10; i++) + { + var index = i; + var unreg = evt.Register(x => + { + if (index % 2 == 0) + { + unregisters[index].UnRegister(); + } + }); + unregisters.Add(unreg); + } + + // Act & Assert + Assert.DoesNotThrow(() => evt.Trigger(1)); + } + + [Test] + public void Context_Handler_Should_Receive_Correct_Data() + { + // Arrange + var evt = new PriorityEvent(); + string? receivedData = null; + + evt.RegisterWithContext(ctx => { receivedData = ctx.Data; }); + + // Act + evt.Trigger("test data", EventPropagation.All); + + // Assert + Assert.That(receivedData, Is.EqualTo("test data")); + } + + [Test] + public void Context_Handler_MarkAsHandled_Should_Stop_UntilHandled_Propagation() + { + // Arrange + var evt = new PriorityEvent(); + var executionOrder = new List(); + + evt.RegisterWithContext(ctx => + { + executionOrder.Add(1); + ctx.MarkAsHandled(); + }, priority: 10); + + evt.RegisterWithContext(ctx => { executionOrder.Add(2); }, priority: 5); + + // Act + evt.Trigger(42, EventPropagation.UntilHandled); + + // Assert + Assert.That(executionOrder, Is.EqualTo(new[] { 1 })); + } + + [Test] + public void Mixed_Normal_And_Context_Handlers_Should_Work_Together() + { + // Arrange + var evt = new PriorityEvent(); + var executionOrder = new List(); + + evt.Register(x => executionOrder.Add("normal"), priority: 5); + evt.RegisterWithContext(ctx => executionOrder.Add("context"), priority: 10); + + // Act + evt.Trigger(1, EventPropagation.All); + + // Assert + Assert.That(executionOrder, Is.EqualTo(new[] { "context", "normal" })); + } + + [Test] + public void UntilHandled_With_Mixed_Handlers_Should_Respect_Priority() + { + // Arrange + var evt = new PriorityEvent(); + var executionOrder = new List(); + + evt.Register(x => executionOrder.Add("normal-low"), priority: 1); + evt.RegisterWithContext(ctx => + { + executionOrder.Add("context-high"); + ctx.MarkAsHandled(); + }, priority: 10); + evt.Register(x => executionOrder.Add("normal-mid"), priority: 5); + + // Act + evt.Trigger(1, EventPropagation.UntilHandled); + + // Assert + Assert.That(executionOrder, Is.EqualTo(new[] { "context-high" })); + } + + [Test] + public void Highest_Propagation_Should_Execute_All_Highest_Priority_Handlers() + { + // Arrange + var evt = new PriorityEvent(); + var executionOrder = new List(); + + evt.Register(x => executionOrder.Add("normal-high"), priority: 10); + evt.RegisterWithContext(ctx => executionOrder.Add("context-high"), priority: 10); + evt.Register(x => executionOrder.Add("normal-low"), priority: 1); + + // Act + evt.Trigger(1, EventPropagation.Highest); + + // Assert + Assert.That(executionOrder.Count, Is.EqualTo(2)); + Assert.That(executionOrder, Does.Contain("normal-high")); + Assert.That(executionOrder, Does.Contain("context-high")); + } +} \ No newline at end of file diff --git a/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs b/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs index 6c9c10a..fba566f 100644 --- a/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs +++ b/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs @@ -30,7 +30,6 @@ public class MicrosoftDiContainerTests } private MicrosoftDiContainer _container = null!; - private readonly Dictionary _mockContextServices = new(); /// /// 测试注册单例实例的功能 @@ -249,12 +248,18 @@ public class MicrosoftDiContainerTests [Test] public void Contains_WithExistingInstance_Should_ReturnTrue() { + // 使用 RegisterSingleton 方法来避免与其他测试方法重复 var instance = new TestService(); - _container.Register(instance); + _container.RegisterSingleton(instance); + + // 验证容器包含该实例 Assert.That(_container.Contains(), Is.True); + // 验证实例确实是单例 + Assert.That(_container.Get(), Is.SameAs(instance)); } + /// /// 测试当不存在实例时检查包含关系应返回 false 的功能 /// @@ -327,6 +332,107 @@ public class MicrosoftDiContainerTests Assert.That(_container.Contains(), Is.True); } + + /// + /// 测试在容器未冻结时调用 CreateScope 应抛出异常 + /// + [Test] + public void CreateScope_Should_Throw_When_Not_Frozen() + { + // Arrange + var container = new MicrosoftDiContainer(); + + // Act & Assert + Assert.Throws(() => container.CreateScope()); + } + + /// + /// 测试 CreateScope 在多线程环境下的线程安全性 + /// + [Test] + public void CreateScope_Should_Be_Thread_Safe() + { + // Arrange + var container = new MicrosoftDiContainer(); + container.RegisterSingleton(new TestService()); + container.Freeze(); + + // Act + var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() => + { + using var scope = container.CreateScope(); + Assert.That(scope, Is.Not.Null); + })).ToArray(); + + // Assert + Assert.DoesNotThrow(() => Task.WaitAll(tasks)); + } + + /// + /// 测试 Get 方法在多线程环境下的线程安全性 + /// + [Test] + public void Get_Should_Be_Thread_Safe() + { + // Arrange + var container = new MicrosoftDiContainer(); + container.RegisterSingleton(new TestService()); + container.Freeze(); + + // Act + var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() => + { + var service = container.Get(); + Assert.That(service, Is.Not.Null); + })).ToArray(); + + // Assert + Assert.DoesNotThrow(() => Task.WaitAll(tasks)); + } + + /// + /// 测试 GetAll 方法在多线程环境下的线程安全性 + /// + [Test] + public void GetAll_Should_Be_Thread_Safe() + { + // Arrange + var container = new MicrosoftDiContainer(); + container.RegisterSingleton(new TestService()); + container.Freeze(); + + // Act + var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() => + { + var services = container.GetAll(); + Assert.That(services, Is.Not.Null); + })).ToArray(); + + // Assert + Assert.DoesNotThrow(() => Task.WaitAll(tasks)); + } + + /// + /// 测试 Contains 方法在多线程环境下的线程安全性 + /// + [Test] + public void Contains_Should_Be_Thread_Safe() + { + // Arrange + var container = new MicrosoftDiContainer(); + container.RegisterSingleton(new TestService()); + container.Freeze(); + + // Act + var tasks = Enumerable.Range(0, 100).Select(_ => Task.Run(() => + { + var contains = container.Contains(); + Assert.That(contains, Is.True); + })).ToArray(); + + // Assert + Assert.DoesNotThrow(() => Task.WaitAll(tasks)); + } } /// diff --git a/GFramework.Core/events/EventBus.cs b/GFramework.Core/events/EventBus.cs index 6e142ae..a67f2b6 100644 --- a/GFramework.Core/events/EventBus.cs +++ b/GFramework.Core/events/EventBus.cs @@ -78,4 +78,27 @@ public class EventBus : IEventBus { _mEvents.GetEvent>().UnRegister(onEvent); } + + /// + /// 注册上下文事件监听器,默认优先级为 0 + /// + /// 事件类型 + /// 事件处理回调函数,接收 EventContext 参数 + /// 反注册接口,用于注销事件监听 + public IUnRegister RegisterWithContext(Action> onEvent) + { + return _mPriorityEvents.GetOrAddEvent>().RegisterWithContext(onEvent); + } + + /// + /// 注册上下文事件监听器,并指定优先级 + /// + /// 事件类型 + /// 事件处理回调函数,接收 EventContext 参数 + /// 优先级,数值越大优先级越高 + /// 反注册接口,用于注销事件监听 + public IUnRegister RegisterWithContext(Action> onEvent, int priority) + { + return _mPriorityEvents.GetOrAddEvent>().RegisterWithContext(onEvent, priority); + } } \ No newline at end of file diff --git a/GFramework.Core/events/PriorityEvent.cs b/GFramework.Core/events/PriorityEvent.cs index 3b07503..c88a235 100644 --- a/GFramework.Core/events/PriorityEvent.cs +++ b/GFramework.Core/events/PriorityEvent.cs @@ -9,19 +9,9 @@ namespace GFramework.Core.events; public class PriorityEvent : IEvent { /// - /// 事件处理器包装类,包含处理器和优先级 + /// 存储已注册的上下文事件处理器列表 /// - private class EventHandler - { - public Action Handler { get; } - public int Priority { get; } - - public EventHandler(Action handler, int priority) - { - Handler = handler; - Priority = priority; - } - } + private readonly List _contextHandlers = new(); /// /// 存储已注册的事件处理器列表 @@ -80,12 +70,29 @@ public class PriorityEvent : IEvent } /// - /// 触发所有已注册的事件处理程序(默认传播模式:All) + /// 注册一个上下文事件监听器,并指定优先级 /// - /// 传递给事件处理程序的参数 - public void Trigger(T t) + /// 要注册的事件处理方法,接收 EventContext 参数 + /// 优先级,数值越大优先级越高 + /// IUnRegister 对象,用于稍后注销该事件监听器 + public IUnRegister RegisterWithContext(Action> onEvent, int priority = 0) { - Trigger(t, EventPropagation.All); + var handler = new ContextEventHandler(onEvent, priority); + _contextHandlers.Add(handler); + + // 按优先级降序排序(高优先级在前) + _contextHandlers.Sort((a, b) => b.Priority.CompareTo(a.Priority)); + + return new DefaultUnRegister(() => UnRegisterContext(onEvent)); + } + + /// + /// 取消指定的上下文事件监听器 + /// + /// 需要被注销的事件处理方法 + public void UnRegisterContext(Action> onEvent) + { + _contextHandlers.RemoveAll(h => h.Handler == onEvent); } /// @@ -93,49 +100,116 @@ public class PriorityEvent : IEvent /// /// 传递给事件处理程序的参数 /// 事件传播模式 - public void Trigger(T t, EventPropagation propagation) + public void Trigger(T t, EventPropagation propagation = EventPropagation.All) { _handled = false; switch (propagation) { case EventPropagation.All: - // 触发所有处理器 - foreach (var handler in _handlers) + // 使用快照避免迭代期间修改 + // 合并所有处理器并按优先级排序 + var allHandlersForAll = _handlers + .Select(h => (h.Priority, Handler: (Action?)(() => h.Handler.Invoke(t)), + ContextHandler: (Action>?)null, IsContext: false)) + .Concat(_contextHandlers + .Select(h => (h.Priority, Handler: (Action?)null, + ContextHandler: (Action>?)h.Handler, IsContext: true))) + .OrderByDescending(h => h.Priority) + .ToList(); + + var contextAll = new EventContext(t); + foreach (var item in allHandlersForAll) { - handler.Handler.Invoke(t); + if (item.IsContext) + { + item.ContextHandler?.Invoke(contextAll); + } + else + { + item.Handler?.Invoke(); + } } + break; case EventPropagation.UntilHandled: - // 触发直到某个处理器标记为已处理 - foreach (var handler in _handlers) + // 合并所有处理器并按优先级排序 + var allHandlers = _handlers + .Select(h => (h.Priority, Handler: (Action?)(() => h.Handler.Invoke(t)), + ContextHandler: (Action>?)null, IsContext: false)) + .Concat(_contextHandlers + .Select(h => (h.Priority, Handler: (Action?)null, + ContextHandler: (Action>?)h.Handler, IsContext: true))) + .OrderByDescending(h => h.Priority) + .ToList(); + + var context = new EventContext(t); + foreach (var item in allHandlers) { - handler.Handler.Invoke(t); - if (_handled) break; + if (item.IsContext) + { + item.ContextHandler?.Invoke(context); + if (context.IsHandled) break; + } + else + { + item.Handler?.Invoke(); + if (_handled) break; // 保持向后兼容 + } } + break; case EventPropagation.Highest: - // 仅触发最高优先级的处理器 - if (_handlers.Count > 0) + // 使用快照避免迭代期间修改 + var normalSnapshot = _handlers.ToArray(); + var contextSnapshot = _contextHandlers.ToArray(); + + // 找到最高优先级 + var highestPriority = int.MinValue; + if (normalSnapshot.Length > 0) + highestPriority = Math.Max(highestPriority, normalSnapshot[0].Priority); + if (contextSnapshot.Length > 0) + highestPriority = Math.Max(highestPriority, contextSnapshot[0].Priority); + + if (highestPriority != int.MinValue) { - var highestPriority = _handlers[0].Priority; - foreach (var handler in _handlers) + // 触发最高优先级的普通处理器 + foreach (var handler in normalSnapshot) { if (handler.Priority < highestPriority) break; handler.Handler.Invoke(t); } + + // 触发最高优先级的上下文处理器 + var contextHighest = new EventContext(t); + foreach (var handler in contextSnapshot) + { + if (handler.Priority < highestPriority) break; + handler.Handler.Invoke(contextHighest); + } } + break; } } /// - /// 标记事件为已处理(用于 UntilHandled 传播模式) + /// 事件处理器包装类,包含处理器和优先级 /// - public void MarkAsHandled() + private sealed class EventHandler(Action handler, int priority) { - _handled = true; + public Action Handler { get; } = handler; + public int Priority { get; } = priority; } -} + + /// + /// 上下文事件处理器包装类,包含处理器和优先级 + /// + private sealed class ContextEventHandler(Action> handler, int priority) + { + public Action> Handler { get; } = handler; + public int Priority { get; } = priority; + } +} \ No newline at end of file diff --git a/GFramework.Core/extensions/SpanExtensions.cs b/GFramework.Core/extensions/SpanExtensions.cs index c5890b7..d24145f 100644 --- a/GFramework.Core/extensions/SpanExtensions.cs +++ b/GFramework.Core/extensions/SpanExtensions.cs @@ -10,7 +10,7 @@ public static class SpanExtensions /// /// 目标类型,必须实现 ISpanParsable 接口 /// 要解析的字符 span - /// 解析结果 + /// 解析结果,失败时为 default(T) /// 如果解析成功返回 true,否则返回 false /// /// @@ -21,7 +21,7 @@ public static class SpanExtensions /// } /// /// - public static bool TryParseValue(this ReadOnlySpan span, out T? result) where T : ISpanParsable + public static bool TryParseValue(this ReadOnlySpan span, out T result) where T : ISpanParsable { return T.TryParse(span, null, out result); } @@ -47,6 +47,7 @@ public static class SpanExtensions if (item.Equals(value)) count++; } + return count; } -} +} \ No newline at end of file diff --git a/GFramework.Core/ioc/MicrosoftDiContainer.cs b/GFramework.Core/ioc/MicrosoftDiContainer.cs index f7eda5a..68b1a86 100644 --- a/GFramework.Core/ioc/MicrosoftDiContainer.cs +++ b/GFramework.Core/ioc/MicrosoftDiContainer.cs @@ -363,25 +363,25 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) /// 服务实例或null public T? Get() where T : class { - if (_provider == null) - { - // 如果容器未冻结,从服务集合中查找已注册的实例 - var serviceType = typeof(T); - var descriptor = GetServicesUnsafe.FirstOrDefault(s => - s.ServiceType == serviceType || serviceType.IsAssignableFrom(s.ServiceType)); - - if (descriptor?.ImplementationInstance is T instance) - { - return instance; - } - - // 在未冻结状态下无法调用工厂方法或创建实例,返回null - return null; - } - _lock.EnterReadLock(); try { + if (_provider == null) + { + // 如果容器未冻结,从服务集合中查找已注册的实例 + var serviceType = typeof(T); + var descriptor = GetServicesUnsafe.FirstOrDefault(s => + s.ServiceType == serviceType || serviceType.IsAssignableFrom(s.ServiceType)); + + if (descriptor?.ImplementationInstance is T instance) + { + return instance; + } + + // 在未冻结状态下无法调用工厂方法或创建实例,返回null + return null; + } + var result = _provider!.GetService(); _logger.Debug(result != null ? $"Retrieved instance: {typeof(T).Name}" @@ -402,18 +402,19 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) /// 服务实例或null public object? Get(Type type) { - if (_provider == null) - { - // 如果容器未冻结,从服务集合中查找已注册的实例 - var descriptor = - GetServicesUnsafe.FirstOrDefault(s => s.ServiceType == type || type.IsAssignableFrom(s.ServiceType)); - - return descriptor?.ImplementationInstance; - } - _lock.EnterReadLock(); try { + if (_provider == null) + { + // 如果容器未冻结,从服务集合中查找已注册的实例 + var descriptor = + GetServicesUnsafe.FirstOrDefault(s => + s.ServiceType == type || type.IsAssignableFrom(s.ServiceType)); + + return descriptor?.ImplementationInstance; + } + var result = _provider!.GetService(type); _logger.Debug(result != null ? $"Retrieved instance: {type.Name}" @@ -491,36 +492,36 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) /// 只读的服务实例列表 public IReadOnlyList GetAll() where T : class { - if (_provider == null) - { - // 如果容器未冻结,从服务集合中获取已注册的实例 - var serviceType = typeof(T); - var registeredServices = GetServicesUnsafe - .Where(s => s.ServiceType == serviceType || serviceType.IsAssignableFrom(s.ServiceType)).ToList(); - - var result = new List(); - foreach (var descriptor in registeredServices) - { - if (descriptor.ImplementationInstance is T instance) - { - result.Add(instance); - } - else if (descriptor.ImplementationFactory != null) - { - // 在未冻结状态下无法调用工厂方法,跳过 - } - else if (descriptor.ImplementationType != null) - { - // 在未冻结状态下无法创建实例,跳过 - } - } - - return result; - } - _lock.EnterReadLock(); try { + if (_provider == null) + { + // 如果容器未冻结,从服务集合中获取已注册的实例 + var serviceType = typeof(T); + var registeredServices = GetServicesUnsafe + .Where(s => s.ServiceType == serviceType || serviceType.IsAssignableFrom(s.ServiceType)).ToList(); + + var result = new List(); + foreach (var descriptor in registeredServices) + { + if (descriptor.ImplementationInstance is T instance) + { + result.Add(instance); + } + else if (descriptor.ImplementationFactory != null) + { + // 在未冻结状态下无法调用工厂方法,跳过 + } + else if (descriptor.ImplementationType != null) + { + // 在未冻结状态下无法创建实例,跳过 + } + } + + return result; + } + var services = _provider!.GetServices().ToList(); _logger.Debug($"Retrieved {services.Count} instances of {typeof(T).Name}"); return services; @@ -539,36 +540,36 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) /// 当容器未冻结时抛出 public IReadOnlyList GetAll(Type type) { - if (_provider == null) - { - // 如果容器未冻结,从服务集合中获取已注册的实例 - var registeredServices = GetServicesUnsafe - .Where(s => s.ServiceType == type || type.IsAssignableFrom(s.ServiceType)) - .ToList(); - - var result = new List(); - foreach (var descriptor in registeredServices) - { - if (descriptor.ImplementationInstance != null) - { - result.Add(descriptor.ImplementationInstance); - } - else if (descriptor.ImplementationFactory != null) - { - // 在未冻结状态下无法调用工厂方法,跳过 - } - else if (descriptor.ImplementationType != null) - { - // 在未冻结状态下无法创建实例,跳过 - } - } - - return result; - } - _lock.EnterReadLock(); try { + if (_provider == null) + { + // 如果容器未冻结,从服务集合中获取已注册的实例 + var registeredServices = GetServicesUnsafe + .Where(s => s.ServiceType == type || type.IsAssignableFrom(s.ServiceType)) + .ToList(); + + var result = new List(); + foreach (var descriptor in registeredServices) + { + if (descriptor.ImplementationInstance != null) + { + result.Add(descriptor.ImplementationInstance); + } + else if (descriptor.ImplementationFactory != null) + { + // 在未冻结状态下无法调用工厂方法,跳过 + } + else if (descriptor.ImplementationType != null) + { + // 在未冻结状态下无法创建实例,跳过 + } + } + + return result; + } + var services = _provider!.GetServices(type).ToList(); _logger.Debug($"Retrieved {services.Count} instances of {type.Name}"); return services.Where(o => o != null).Cast().ToList(); @@ -605,12 +606,12 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) /// true表示包含该类型实例,false表示不包含 public bool Contains() where T : class { - if (_provider == null) - return GetServicesUnsafe.Any(s => s.ServiceType == typeof(T)); - _lock.EnterReadLock(); try { + if (_provider == null) + return GetServicesUnsafe.Any(s => s.ServiceType == typeof(T)); + return _provider.GetService() != null; } finally @@ -706,16 +707,17 @@ public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) /// 当容器未冻结时抛出 public IServiceScope CreateScope() { - if (_provider == null) - { - const string errorMsg = "Cannot create scope before container is frozen"; - _logger.Error(errorMsg); - throw new InvalidOperationException(errorMsg); - } - _lock.EnterReadLock(); try { + // 在锁内检查,避免竞态条件 + if (!_frozen || _provider == null) + { + const string errorMsg = "Cannot create scope before container is frozen"; + _logger.Error(errorMsg); + throw new InvalidOperationException(errorMsg); + } + var scope = _provider.CreateScope(); _logger.Debug("Service scope created"); return scope;