From 55ec42a670fd01fe5979cf1337b897a7e05de2f1 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Sat, 14 Feb 2026 10:06:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(ioc):=20=E6=9B=BF=E6=8D=A2=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89IoC=E5=AE=B9=E5=99=A8=E4=B8=BAMicrosoft.Exten?= =?UTF-8?q?sions.DependencyInjection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除原有的IocContainer实现 - 添加MicrosoftDiContainer作为Microsoft.Extensions.DependencyInjection的适配器 - 修改ArchitectureServices使用MicrosoftDiContainer替代IocContainer - 更新所有相关测试类使用MicrosoftDiContainer - 添加Mediator和Microsoft.Extensions.DependencyInjection包引用 - 扩展IIocContainer接口支持更多注册方法 - 在架构初始化中添加Mediator服务注册 --- .../GFramework.Core.Abstractions.csproj | 1 + .../ioc/IIocContainer.cs | 27 +- .../architecture/ArchitectureContextTests.cs | 8 +- .../architecture/ArchitectureServicesTests.cs | 4 +- .../architecture/GameContextTests.cs | 2 +- .../command/AbstractAsyncCommandTests.cs | 4 +- ...rTests.cs => MicrosoftDiContainerTests.cs} | 12 +- .../query/AbstractAsyncQueryTests.cs | 4 +- .../state/StateMachineSystemTests.cs | 6 +- .../utility/AbstractContextUtilityTests.cs | 4 +- GFramework.Core/GFramework.Core.csproj | 6 + GFramework.Core/architecture/Architecture.cs | 4 + .../architecture/ArchitectureServices.cs | 2 +- GFramework.Core/ioc/IocContainer.cs | 452 --------------- GFramework.Core/ioc/MicrosoftDiContainer.cs | 516 ++++++++++++++++++ 15 files changed, 576 insertions(+), 476 deletions(-) rename GFramework.Core.Tests/ioc/{IocContainerTests.cs => MicrosoftDiContainerTests.cs} (96%) delete mode 100644 GFramework.Core/ioc/IocContainer.cs create mode 100644 GFramework.Core/ioc/MicrosoftDiContainer.cs diff --git a/GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj b/GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj index 3f08ecf..3068015 100644 --- a/GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj +++ b/GFramework.Core.Abstractions/GFramework.Core.Abstractions.csproj @@ -25,5 +25,6 @@ all runtime; build; native; contentfiles; analyzers + diff --git a/GFramework.Core.Abstractions/ioc/IIocContainer.cs b/GFramework.Core.Abstractions/ioc/IIocContainer.cs index 6d8cba4..06c1538 100644 --- a/GFramework.Core.Abstractions/ioc/IIocContainer.cs +++ b/GFramework.Core.Abstractions/ioc/IIocContainer.cs @@ -1,5 +1,6 @@ using GFramework.Core.Abstractions.rule; using GFramework.Core.Abstractions.system; +using Microsoft.Extensions.DependencyInjection; namespace GFramework.Core.Abstractions.ioc; @@ -19,6 +20,14 @@ public interface IIocContainer : IContextAware /// 当该类型已经注册过单例时抛出异常 void RegisterSingleton(T instance); + /// + /// 注册单例服务,指定服务类型和实现类型 + /// 创建单例实例并在容器中注册 + /// + /// 服务接口或基类类型 + /// 具体的实现类型 + void RegisterSingleton() + where TImpl : class, TService where TService : class; /// /// 注册多个实例 @@ -47,6 +56,14 @@ public interface IIocContainer : IContextAware /// 要注册的实例对象 void Register(Type type, object instance); + /// + /// 注册工厂方法来创建服务实例 + /// 通过委托函数动态创建服务实例 + /// + /// 服务类型 + /// 创建服务实例的工厂委托函数 + void RegisterFactory(Func factory); + #endregion #region Get Methods @@ -117,7 +134,7 @@ public interface IIocContainer : IContextAware /// /// 要检查的类型 /// 如果容器中包含指定类型的实例则返回true,否则返回false - bool Contains(); + bool Contains() where T : class; /// /// 判断容器中是否包含某个具体的实例对象 @@ -133,8 +150,16 @@ public interface IIocContainer : IContextAware /// /// 冻结容器,防止后续修改 + /// 调用此方法后,容器将变为只读状态,不能再注册新的服务实例 /// void Freeze(); + /// + /// 获取底层的服务集合 + /// 提供对内部IServiceCollection的访问权限,用于高级配置和自定义操作 + /// + /// 底层的IServiceCollection实例 + IServiceCollection Services { get; } + #endregion } \ No newline at end of file diff --git a/GFramework.Core.Tests/architecture/ArchitectureContextTests.cs b/GFramework.Core.Tests/architecture/ArchitectureContextTests.cs index 059c5ac..e00fd86 100644 --- a/GFramework.Core.Tests/architecture/ArchitectureContextTests.cs +++ b/GFramework.Core.Tests/architecture/ArchitectureContextTests.cs @@ -46,13 +46,13 @@ public class ArchitectureContextTests [SetUp] public void SetUp() { - // 初始化 LoggerFactoryResolver 以支持 IocContainer + // 初始化 LoggerFactoryResolver 以支持 MicrosoftDiContainer LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); - _container = new IocContainer(); + _container = new MicrosoftDiContainer(); // 直接初始化 logger 字段 - var loggerField = typeof(IocContainer).GetField("_logger", + var loggerField = typeof(MicrosoftDiContainer).GetField("_logger", BindingFlags.NonPublic | BindingFlags.Instance); loggerField?.SetValue(_container, LoggerFactoryResolver.Provider.CreateLogger(nameof(ArchitectureContextTests))); @@ -75,7 +75,7 @@ public class ArchitectureContextTests } private ArchitectureContext? _context; - private IocContainer? _container; + private MicrosoftDiContainer? _container; private EventBus? _eventBus; private CommandExecutor? _commandBus; private QueryExecutor? _queryBus; diff --git a/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs b/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs index 9cf748f..7c1d2ac 100644 --- a/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs +++ b/GFramework.Core.Tests/architecture/ArchitectureServicesTests.cs @@ -59,7 +59,7 @@ public class ArchitectureServicesTests public void Container_Should_Be_Instance_Of_IocContainer() { Assert.That(_services!.Container, Is.InstanceOf()); - Assert.That(_services.Container, Is.InstanceOf()); + Assert.That(_services.Container, Is.InstanceOf()); } /// @@ -218,7 +218,7 @@ public class ArchitectureServicesTests public class TestArchitectureContextV3 : IArchitectureContext { - private readonly IocContainer _container = new(); + private readonly MicrosoftDiContainer _container = new(); private readonly DefaultEnvironment _environment = new(); public int Id { get; init; } diff --git a/GFramework.Core.Tests/architecture/GameContextTests.cs b/GFramework.Core.Tests/architecture/GameContextTests.cs index 9bd4ef8..054b70b 100644 --- a/GFramework.Core.Tests/architecture/GameContextTests.cs +++ b/GFramework.Core.Tests/architecture/GameContextTests.cs @@ -229,7 +229,7 @@ public class TestArchitecture : Architecture /// public class TestArchitectureContext : IArchitectureContext { - private readonly IocContainer _container = new(); + private readonly MicrosoftDiContainer _container = new(); /// /// 获取依赖注入容器 diff --git a/GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs b/GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs index c9863dc..6f445f1 100644 --- a/GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs +++ b/GFramework.Core.Tests/command/AbstractAsyncCommandTests.cs @@ -32,7 +32,7 @@ public class AbstractAsyncCommandTests [SetUp] public void SetUp() { - _container = new IocContainer(); + _container = new MicrosoftDiContainer(); _container.RegisterPlurality(new EventBus()); _container.RegisterPlurality(new CommandExecutor()); _container.RegisterPlurality(new QueryExecutor()); @@ -42,7 +42,7 @@ public class AbstractAsyncCommandTests } private ArchitectureContext _context = null!; - private IocContainer _container = null!; + private MicrosoftDiContainer _container = null!; /// /// 测试异步命令无返回值版本的基础实现 diff --git a/GFramework.Core.Tests/ioc/IocContainerTests.cs b/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs similarity index 96% rename from GFramework.Core.Tests/ioc/IocContainerTests.cs rename to GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs index 7f3d785..6c9c10a 100644 --- a/GFramework.Core.Tests/ioc/IocContainerTests.cs +++ b/GFramework.Core.Tests/ioc/MicrosoftDiContainerTests.cs @@ -10,7 +10,7 @@ namespace GFramework.Core.Tests.ioc; /// 测试 IoC 容器功能的单元测试类 /// [TestFixture] -public class IocContainerTests +public class MicrosoftDiContainerTests { /// /// 在每个测试方法执行前进行设置 @@ -18,18 +18,18 @@ public class IocContainerTests [SetUp] public void SetUp() { - // 初始化 LoggerFactoryResolver 以支持 IocContainer + // 初始化 LoggerFactoryResolver 以支持 MicrosoftDiContainer LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); - _container = new IocContainer(); + _container = new MicrosoftDiContainer(); // 直接初始化 logger 字段 - var loggerField = typeof(IocContainer).GetField("_logger", + var loggerField = typeof(MicrosoftDiContainer).GetField("_logger", BindingFlags.NonPublic | BindingFlags.Instance); loggerField?.SetValue(_container, - LoggerFactoryResolver.Provider.CreateLogger(nameof(IocContainer))); + LoggerFactoryResolver.Provider.CreateLogger(nameof(MicrosoftDiContainer))); } - private IocContainer _container = null!; + private MicrosoftDiContainer _container = null!; private readonly Dictionary _mockContextServices = new(); /// diff --git a/GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs b/GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs index c908973..0019970 100644 --- a/GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs +++ b/GFramework.Core.Tests/query/AbstractAsyncQueryTests.cs @@ -30,7 +30,7 @@ public class AbstractAsyncQueryTests [SetUp] public void SetUp() { - _container = new IocContainer(); + _container = new MicrosoftDiContainer(); _container.RegisterPlurality(new EventBus()); _container.RegisterPlurality(new CommandExecutor()); _container.RegisterPlurality(new QueryExecutor()); @@ -40,7 +40,7 @@ public class AbstractAsyncQueryTests } private ArchitectureContext _context = null!; - private IocContainer _container = null!; + private MicrosoftDiContainer _container = null!; /// /// 测试异步查询的基础实现 diff --git a/GFramework.Core.Tests/state/StateMachineSystemTests.cs b/GFramework.Core.Tests/state/StateMachineSystemTests.cs index 632cf6b..b05ddc5 100644 --- a/GFramework.Core.Tests/state/StateMachineSystemTests.cs +++ b/GFramework.Core.Tests/state/StateMachineSystemTests.cs @@ -37,14 +37,14 @@ public class StateMachineSystemTests [SetUp] public void SetUp() { - // 初始化 LoggerFactoryResolver 以支持 IocContainer + // 初始化 LoggerFactoryResolver 以支持 MicrosoftDiContainer LoggerFactoryResolver.Provider = new ConsoleLoggerFactoryProvider(); _eventBus = new EventBus(); - var container = new IocContainer(); + var container = new MicrosoftDiContainer(); // 直接初始化 logger 字段 - var loggerField = typeof(IocContainer).GetField("_logger", + var loggerField = typeof(MicrosoftDiContainer).GetField("_logger", BindingFlags.NonPublic | BindingFlags.Instance); loggerField?.SetValue(container, LoggerFactoryResolver.Provider.CreateLogger(nameof(StateMachineSystemTests))); diff --git a/GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs b/GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs index 8339e2c..b970c31 100644 --- a/GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs +++ b/GFramework.Core.Tests/utility/AbstractContextUtilityTests.cs @@ -30,7 +30,7 @@ public class AbstractContextUtilityTests [SetUp] public void SetUp() { - _container = new IocContainer(); + _container = new MicrosoftDiContainer(); _container.RegisterPlurality(new EventBus()); _container.RegisterPlurality(new CommandExecutor()); _container.RegisterPlurality(new QueryExecutor()); @@ -40,7 +40,7 @@ public class AbstractContextUtilityTests } private ArchitectureContext _context = null!; - private IocContainer _container = null!; + private MicrosoftDiContainer _container = null!; /// /// 测试AbstractContextUtility实现IContextUtility接口 diff --git a/GFramework.Core/GFramework.Core.csproj b/GFramework.Core/GFramework.Core.csproj index 2775e88..3897ac1 100644 --- a/GFramework.Core/GFramework.Core.csproj +++ b/GFramework.Core/GFramework.Core.csproj @@ -12,5 +12,11 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/GFramework.Core/architecture/Architecture.cs b/GFramework.Core/architecture/Architecture.cs index e045b81..d5902ca 100644 --- a/GFramework.Core/architecture/Architecture.cs +++ b/GFramework.Core/architecture/Architecture.cs @@ -10,6 +10,7 @@ using GFramework.Core.Abstractions.utility; using GFramework.Core.environment; using GFramework.Core.extensions; using GFramework.Core.logging; +using Microsoft.Extensions.DependencyInjection; using IDisposable = GFramework.Core.Abstractions.lifecycle.IDisposable; namespace GFramework.Core.architecture; @@ -540,6 +541,9 @@ public abstract class Architecture( // 为服务设置上下文 Services.SetContext(_context); + // 添加 Mediator + Container.Services.AddMediator(); + // === 用户 Init === _logger.Debug("Calling user Init()"); Init(); diff --git a/GFramework.Core/architecture/ArchitectureServices.cs b/GFramework.Core/architecture/ArchitectureServices.cs index bf5d197..bd6656a 100644 --- a/GFramework.Core/architecture/ArchitectureServices.cs +++ b/GFramework.Core/architecture/ArchitectureServices.cs @@ -47,7 +47,7 @@ public class ArchitectureServices : IArchitectureServices /// public ArchitectureServices() { - Container = new IocContainer(); + Container = new MicrosoftDiContainer(); // 创建服务实例 _eventBus = new EventBus(); diff --git a/GFramework.Core/ioc/IocContainer.cs b/GFramework.Core/ioc/IocContainer.cs deleted file mode 100644 index 5f4bf9d..0000000 --- a/GFramework.Core/ioc/IocContainer.cs +++ /dev/null @@ -1,452 +0,0 @@ -using GFramework.Core.Abstractions.ioc; -using GFramework.Core.Abstractions.logging; -using GFramework.Core.Abstractions.system; -using GFramework.Core.logging; -using GFramework.Core.rule; - -namespace GFramework.Core.ioc; - -/// -/// IOC容器类,用于管理对象的注册和获取 -/// -public class IocContainer : ContextAwareBase, IIocContainer -{ - #region Lock - - /// - /// 读写锁对象,用于控制多线程环境下对共享资源的访问 - /// 使用ReaderWriterLockSlim提供高效的读写锁定机制 - /// 配置为不支持递归锁,避免死锁风险 - /// - private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.NoRecursion); - - #endregion - - #region Flag - - /// - /// 冻结标志位,用于标识对象是否已被冻结 - /// true表示对象已冻结,不可修改;false表示对象可正常修改 - /// - private volatile bool _frozen; - - #endregion - - #region Core - - /// - /// 存储所有已注册对象实例的集合,用于跟踪和管理容器中的所有对象 - /// 使用HashSet确保对象唯一性,避免重复注册同一实例 - /// - private readonly HashSet _objects = []; - - /// - /// 类型索引字典,用于快速查找指定类型的所有实例 - /// 键为类型对象,值为该类型对应的所有实例集合 - /// - private readonly Dictionary> _typeIndex = new(); - - private ILogger _logger = null!; - - #endregion - - #region Register - - /// - /// 当上下文准备就绪时调用此方法,用于初始化日志记录器。 - /// - protected override void OnContextReady() - { - // 创建日志记录器实例,并将其赋值给_logger字段 - _logger = - LoggerFactoryResolver.Provider.CreateLogger(nameof(IocContainer)); - } - - - /// - /// 注册单例 - /// 一个类型只允许一个实例 - /// - /// 要注册为单例的类型 - /// 要注册的单例实例 - /// 当该类型已经注册过单例时抛出异常 - public void RegisterSingleton(T instance) - { - var type = typeof(T); - _lock.EnterWriteLock(); - try - { - // 检查容器是否已被冻结 - if (_frozen) - { - var errorMsg = "IocContainer is frozen"; - _logger.Error(errorMsg); - throw new InvalidOperationException(errorMsg); - } - - // 检查该类型是否已经注册过单例 - if (_typeIndex.TryGetValue(type, out var set) && set.Count > 0) - { - var errorMsg = $"Singleton already registered for type: {type.Name}"; - _logger.Error(errorMsg); - throw new InvalidOperationException(errorMsg); - } - - RegisterInternal(type, instance!); - _logger.Debug($"Singleton registered: {type.Name}"); - } - finally - { - _lock.ExitWriteLock(); - } - } - - /// - /// 注册多个实例 - /// 将实例注册到其实现的所有接口和具体类型上 - /// - /// 要注册的实例 - public void RegisterPlurality(object instance) - { - var concreteType = instance.GetType(); - var interfaces = concreteType.GetInterfaces(); - - _lock.EnterWriteLock(); - try - { - // 注册具体类型 - RegisterInternal(concreteType, instance); - - // 注册所有接口类型 - foreach (var itf in interfaces) RegisterInternal(itf, instance); - } - finally - { - _lock.ExitWriteLock(); - } - } - - /// - /// 在内部字典中注册指定类型和实例的映射关系 - /// - /// 要注册的类型 - /// 要注册的实例 - private void RegisterInternal(Type type, object instance) - { - if (_frozen) - { - const string errorMsg = "IocContainer is frozen"; - _logger.Error(errorMsg); - throw new InvalidOperationException(errorMsg); - } - - _objects.Add(instance); - - if (!_typeIndex.TryGetValue(type, out var set)) - { - set = []; - _typeIndex[type] = set; - } - - set.Add(instance); - } - - - /// - /// 注册系统实例,将其绑定到其所有实现的接口上 - /// - /// 系统实例对象 - public void RegisterSystem(ISystem system) - { - RegisterPlurality(system); - } - - - /// - /// 注册指定类型的实例到容器中 - /// - /// 要注册的实例类型 - /// 要注册的实例对象,不能为null - public void Register(T instance) - { - // 获取写锁以确保线程安全 - _lock.EnterWriteLock(); - try - { - RegisterInternal(typeof(T), instance!); - } - finally - { - // 释放写锁 - _lock.ExitWriteLock(); - } - } - - /// - /// 注册指定类型的实例到容器中 - /// - /// 要注册的实例类型 - /// 要注册的实例对象 - public void Register(Type type, object instance) - { - // 获取写锁以确保线程安全 - _lock.EnterWriteLock(); - try - { - RegisterInternal(type, instance); - } - finally - { - // 释放写锁 - _lock.ExitWriteLock(); - } - } - - #endregion - - #region Get - - /// - /// 获取单个实例(通常用于具体类型) - /// 如果存在多个,只返回第一个 - /// - /// 期望获取的实例类型 - /// 找到的第一个实例;如果未找到则返回 null - public T? Get() where T : class - { - _lock.EnterReadLock(); - try - { - if (_typeIndex.TryGetValue(typeof(T), out var set) && set.Count > 0) - { - var result = set.First() as T; - _logger.Debug($"Retrieved instance: {typeof(T).Name}"); - return result; - } - - _logger.Debug($"No instance found for type: {typeof(T).Name}"); - return null; - } - finally - { - _lock.ExitReadLock(); - } - } - - /// - /// 获取指定类型的单个实例 - /// 如果存在多个,只返回第一个 - /// - /// 期望获取的实例类型 - /// 找到的第一个实例;如果未找到则返回 null - public object? Get(Type type) - { - _lock.EnterReadLock(); - try - { - if (_typeIndex.TryGetValue(type, out var set) && set.Count > 0) - { - var result = set.First(); - _logger.Debug($"Retrieved instance: {type.Name}"); - return result; - } - - _logger.Debug($"No instance found for type: {type.Name}"); - return null; - } - finally - { - _lock.ExitReadLock(); - } - } - - - /// - /// 获取指定类型的必需实例 - /// - /// 期望获取的实例类型 - /// 找到的唯一实例 - /// 当没有注册实例或注册了多个实例时抛出 - public T GetRequired() where T : class - { - var list = GetAll(); - - switch (list.Count) - { - case 0: - var notFoundMsg = $"No instance registered for {typeof(T).Name}"; - _logger.Error(notFoundMsg); - throw new InvalidOperationException(notFoundMsg); - - case 1: - _logger.Debug($"Retrieved required instance: {typeof(T).Name}"); - return list[0]; - - default: - var multipleMsg = $"Multiple instances registered for {typeof(T).Name}"; - _logger.Error(multipleMsg); - throw new InvalidOperationException(multipleMsg); - } - } - - /// - /// 获取指定类型的必需实例 - /// - /// 期望获取的实例类型 - /// 找到的唯一实例 - /// 当没有注册实例或注册了多个实例时抛出 - public object GetRequired(Type type) - { - var list = GetAll(type); - - switch (list.Count) - { - case 0: - var notFoundMsg = $"No instance registered for {type.Name}"; - _logger.Error(notFoundMsg); - throw new InvalidOperationException(notFoundMsg); - - case 1: - _logger.Debug($"Retrieved required instance: {type.Name}"); - return list[0]; - - default: - var multipleMsg = $"Multiple instances registered for {type.Name}"; - _logger.Error(multipleMsg); - throw new InvalidOperationException(multipleMsg); - } - } - - /// - /// 获取指定类型的所有实例(接口 / 抽象类推荐使用) - /// - /// 期望获取的实例类型 - /// 所有符合条件的实例列表;如果没有则返回空数组 - public IReadOnlyList GetAll() where T : class - { - _lock.EnterReadLock(); - try - { - return _typeIndex.TryGetValue(typeof(T), out var set) - ? set.Cast().ToList() // 快照 - : Array.Empty(); - } - finally - { - _lock.ExitReadLock(); - } - } - - /// - /// 获取指定类型的所有实例 - /// - /// 期望获取的实例类型 - /// 所有符合条件的实例列表;如果没有则返回空数组 - public IReadOnlyList GetAll(Type type) - { - _lock.EnterReadLock(); - try - { - return _typeIndex.TryGetValue(type, out var set) - ? set.ToList() // 快照 - : Array.Empty(); - } - finally - { - _lock.ExitReadLock(); - } - } - - - /// - /// 获取并排序(系统调度专用) - /// - /// 期望获取的实例类型 - /// 比较器委托,定义排序规则 - /// 按指定方式排序后的实例列表 - public IReadOnlyList GetAllSorted(Comparison comparison) - where T : class - { - var list = GetAll().ToList(); - list.Sort(comparison); - return list; - } - - #endregion - - #region Utility - - /// - /// 检查容器中是否包含指定类型的实例 - /// - /// 要检查的类型 - /// 如果容器中包含指定类型的实例则返回true,否则返回false - public bool Contains() - { - _lock.EnterReadLock(); - try - { - return _typeIndex.TryGetValue(typeof(T), out var set) && set.Count > 0; - } - finally - { - _lock.ExitReadLock(); - } - } - - /// - /// 清空容器中的所有实例 - /// - public void Clear() - { - _lock.EnterWriteLock(); - try - { - _objects.Clear(); - _typeIndex.Clear(); - } - finally - { - _lock.ExitWriteLock(); - } - } - - /// - /// 判断容器中是否包含某个具体的实例对象 - /// - /// 待查询的实例对象 - /// 若容器中包含该实例则返回true,否则返回false - public bool ContainsInstance(object instance) - { - _lock.EnterReadLock(); - try - { - return _objects.Contains(instance); - } - finally - { - _lock.ExitReadLock(); - } - } - - - /// - /// 冻结容器,防止后续修改 - /// - public void Freeze() - { - // 获取写锁以确保线程安全的状态修改 - _lock.EnterWriteLock(); - try - { - _frozen = true; - _logger.Info("IOC Container frozen - no further registrations allowed"); - } - finally - { - _lock.ExitWriteLock(); - } - } - - #endregion -} \ No newline at end of file diff --git a/GFramework.Core/ioc/MicrosoftDiContainer.cs b/GFramework.Core/ioc/MicrosoftDiContainer.cs new file mode 100644 index 0000000..5ea7392 --- /dev/null +++ b/GFramework.Core/ioc/MicrosoftDiContainer.cs @@ -0,0 +1,516 @@ +using GFramework.Core.Abstractions.ioc; +using GFramework.Core.Abstractions.logging; +using GFramework.Core.Abstractions.system; +using GFramework.Core.logging; +using GFramework.Core.rule; +using Microsoft.Extensions.DependencyInjection; + +namespace GFramework.Core.ioc; + +/// +/// Microsoft.Extensions.DependencyInjection 适配器 +/// 将 Microsoft DI 包装为 IIocContainer 接口实现 +/// 提供线程安全的依赖注入容器功能 +/// +/// 可选的IServiceCollection实例,默认创建新的ServiceCollection +public class MicrosoftDiContainer(IServiceCollection? serviceCollection = null) : ContextAwareBase, IIocContainer +{ + #region Context Ready + + /// + /// 上下文准备就绪时的回调方法 + /// 初始化日志记录器实例 + /// + protected override void OnContextReady() + { + _logger = LoggerFactoryResolver.Provider.CreateLogger(nameof(MicrosoftDiContainer)); + } + + #endregion + + #region Fields + + /// + /// 服务提供者,在容器冻结后构建,用于解析服务实例 + /// + private IServiceProvider? _provider; + + /// + /// 容器冻结状态标志,true表示容器已冻结不可修改 + /// + private volatile bool _frozen; + + /// + /// 读写锁,确保多线程环境下的线程安全操作 + /// + private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.NoRecursion); + + /// + /// 已注册实例的集合,用于快速检查实例是否存在 + /// + private readonly HashSet _registeredInstances = []; + + /// + /// 日志记录器,用于记录容器操作日志 + /// + private ILogger _logger = null!; + + #endregion + + #region Register + + /// + /// 注册单例服务实例 + /// 确保同一类型只能注册一次,避免重复注册 + /// + /// 服务类型 + /// 要注册的实例对象 + /// 当容器已冻结或类型已被注册时抛出 + public void RegisterSingleton(T instance) + { + var type = typeof(T); + _lock.EnterWriteLock(); + try + { + ThrowIfFrozen(); + + // 检查是否已注册该类型,防止重复注册 + if (Services.Any(s => s.ServiceType == type)) + { + var errorMsg = $"Singleton already registered for type: {type.Name}"; + _logger.Error(errorMsg); + throw new InvalidOperationException(errorMsg); + } + + Services.AddSingleton(type, instance!); + _registeredInstances.Add(instance!); + _logger.Debug($"Singleton registered: {type.Name}"); + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// + /// 注册单例服务,指定服务类型和实现类型 + /// 直接使用底层DI容器注册类型映射关系 + /// + /// 服务接口或基类类型 + /// 具体的实现类型 + public void RegisterSingleton() + where TImpl : class, TService where TService : class + { + Services.AddSingleton(); + } + + /// + /// 注册多个实例到其所有接口和具体类型 + /// 实现一个实例支持多种接口类型的解析 + /// + /// 要注册的对象实例 + /// 当容器已冻结时抛出 + public void RegisterPlurality(object instance) + { + var concreteType = instance.GetType(); + var interfaces = concreteType.GetInterfaces(); + + _lock.EnterWriteLock(); + try + { + ThrowIfFrozen(); + + // 注册具体类型映射 + Services.AddSingleton(concreteType, instance); + + // 注册所有接口类型映射(指向同一实例) + foreach (var interfaceType in interfaces) + { + Services.AddSingleton(interfaceType, _ => instance); + } + + _registeredInstances.Add(instance); + _logger.Debug($"Plurality registered: {concreteType.Name} with {interfaces.Length} interfaces"); + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// + /// 注册系统实例 + /// 通过RegisterPlurality方法注册ISystem类型实例 + /// + /// 要注册的系统实例 + public void RegisterSystem(ISystem system) + { + RegisterPlurality(system); + } + + /// + /// 注册指定泛型类型的服务实例 + /// + /// 服务类型 + /// 要注册的实例对象 + /// 当容器已冻结时抛出 + public void Register(T instance) + { + _lock.EnterWriteLock(); + try + { + ThrowIfFrozen(); + Services.AddSingleton(typeof(T), instance!); + _registeredInstances.Add(instance!); + _logger.Debug($"Registered: {typeof(T).Name}"); + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// + /// 注册指定类型的服务实例 + /// + /// 服务类型 + /// 要注册的实例对象 + /// 当容器已冻结时抛出 + public void Register(Type type, object instance) + { + _lock.EnterWriteLock(); + try + { + ThrowIfFrozen(); + Services.AddSingleton(type, instance); + _registeredInstances.Add(instance); + _logger.Debug($"Registered: {type.Name}"); + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// + /// 注册工厂方法来创建服务实例 + /// 通过委托函数动态创建服务实例,支持依赖注入 + /// + /// 服务类型 + /// 创建服务实例的工厂委托函数,接收IServiceProvider参数 + public void RegisterFactory(Func factory) + { + ThrowIfFrozen(); + Services.AddSingleton(factory); + } + + #endregion + + #region Get + + /// + /// 获取指定泛型类型的服务实例 + /// 返回第一个匹配的注册实例,如果不存在则返回null + /// + /// 服务类型 + /// 服务实例或null + /// 当容器未冻结时抛出 + public T? Get() where T : class + { + EnsureProvider(); + _lock.EnterReadLock(); + try + { + var result = _provider!.GetService(); + _logger.Debug(result != null + ? $"Retrieved instance: {typeof(T).Name}" + : $"No instance found for type: {typeof(T).Name}"); + return result; + } + finally + { + _lock.ExitReadLock(); + } + } + + /// + /// 获取指定类型的服务实例 + /// 返回第一个匹配的注册实例,如果不存在则返回null + /// + /// 服务类型 + /// 服务实例或null + /// 当容器未冻结时抛出 + public object? Get(Type type) + { + EnsureProvider(); + _lock.EnterReadLock(); + try + { + var result = _provider!.GetService(type); + _logger.Debug(result != null + ? $"Retrieved instance: {type.Name}" + : $"No instance found for type: {type.Name}"); + return result; + } + finally + { + _lock.ExitReadLock(); + } + } + + /// + /// 获取指定泛型类型的必需服务实例 + /// 必须存在且唯一,否则抛出异常 + /// + /// 服务类型 + /// 唯一的服务实例 + /// 当实例不存在或多于一个时抛出 + public T GetRequired() where T : class + { + var list = GetAll(); + + switch (list.Count) + { + case 0: + var notFoundMsg = $"No instance registered for {typeof(T).Name}"; + _logger.Error(notFoundMsg); + throw new InvalidOperationException(notFoundMsg); + + case 1: + _logger.Debug($"Retrieved required instance: {typeof(T).Name}"); + return list[0]; + + default: + var multipleMsg = $"Multiple instances registered for {typeof(T).Name}"; + _logger.Error(multipleMsg); + throw new InvalidOperationException(multipleMsg); + } + } + + /// + /// 获取指定类型的必需服务实例 + /// 必须存在且唯一,否则抛出异常 + /// + /// 服务类型 + /// 唯一的服务实例 + /// 当实例不存在或多于一个时抛出 + public object GetRequired(Type type) + { + var list = GetAll(type); + + switch (list.Count) + { + case 0: + var notFoundMsg = $"No instance registered for {type.Name}"; + _logger.Error(notFoundMsg); + throw new InvalidOperationException(notFoundMsg); + + case 1: + _logger.Debug($"Retrieved required instance: {type.Name}"); + return list[0]; + + default: + var multipleMsg = $"Multiple instances registered for {type.Name}"; + _logger.Error(multipleMsg); + throw new InvalidOperationException(multipleMsg); + } + } + + /// + /// 获取指定泛型类型的所有服务实例 + /// + /// 服务类型 + /// 只读的服务实例列表 + /// 当容器未冻结时抛出 + public IReadOnlyList GetAll() where T : class + { + EnsureProvider(); + _lock.EnterReadLock(); + try + { + var services = _provider!.GetServices().ToList(); + _logger.Debug($"Retrieved {services.Count} instances of {typeof(T).Name}"); + return services; + } + finally + { + _lock.ExitReadLock(); + } + } + + /// + /// 获取指定类型的所有服务实例 + /// + /// 服务类型 + /// 只读的服务实例列表 + /// 当容器未冻结时抛出 + public IReadOnlyList GetAll(Type type) + { + EnsureProvider(); + _lock.EnterReadLock(); + try + { + var services = _provider!.GetServices(type).ToList(); + _logger.Debug($"Retrieved {services.Count} instances of {type.Name}"); + return services.Where(o => o != null).Cast().ToList(); + } + finally + { + _lock.ExitReadLock(); + } + } + + /// + /// 获取并排序指定泛型类型的所有服务实例 + /// 主要用于系统调度场景 + /// + /// 服务类型 + /// 比较委托,用于定义排序规则 + /// 排序后的只读服务实例列表 + public IReadOnlyList GetAllSorted(Comparison comparison) where T : class + { + var list = GetAll().ToList(); + list.Sort(comparison); + return list; + } + + #endregion + + #region Utility + + /// + /// 检查容器中是否包含指定泛型类型的实例 + /// 根据容器状态选择不同的检查策略 + /// + /// 要检查的类型 + /// true表示包含该类型实例,false表示不包含 + public bool Contains() where T : class + { + if (_provider == null) + return Services.Any(s => s.ServiceType == typeof(T)); + + _lock.EnterReadLock(); + try + { + return _provider.GetService() != null; + } + finally + { + _lock.ExitReadLock(); + } + } + + /// + /// 判断容器中是否包含某个具体的实例对象 + /// 通过已注册实例集合进行快速查找 + /// + /// 要检查的实例对象 + /// true表示包含该实例,false表示不包含 + public bool ContainsInstance(object instance) + { + _lock.EnterReadLock(); + try + { + return _registeredInstances.Contains(instance); + } + finally + { + _lock.ExitReadLock(); + } + } + + /// + /// 清空容器中的所有实例和服务注册 + /// 只有在容器未冻结状态下才能执行清空操作 + /// + public void Clear() + { + _lock.EnterWriteLock(); + try + { + // 冻结的容器不允许清空操作 + if (_frozen) + { + _logger.Warn("Cannot clear frozen container"); + return; + } + + Services.Clear(); + _registeredInstances.Clear(); + _provider = null; + _logger.Info("Container cleared"); + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// + /// 冻结容器并构建ServiceProvider + /// 冻结后容器变为只读状态,不能再注册新服务 + /// + public void Freeze() + { + _lock.EnterWriteLock(); + try + { + // 防止重复冻结 + if (_frozen) + { + _logger.Warn("Container already frozen"); + return; + } + + _provider = Services.BuildServiceProvider(); + _frozen = true; + _logger.Info("IOC Container frozen - ServiceProvider built"); + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// + /// 获取底层的服务集合 + /// 提供对内部IServiceCollection的访问权限,用于高级配置和自定义操作 + /// + /// 底层的IServiceCollection实例 + public IServiceCollection Services { get; } = serviceCollection ?? new ServiceCollection(); + + #endregion + + #region Helper Methods + + /// + /// 检查容器是否已冻结,如果已冻结则抛出异常 + /// 用于保护注册操作的安全性 + /// + /// 当容器已冻结时抛出 + private void ThrowIfFrozen() + { + if (_frozen) + { + const string errorMsg = "MicrosoftDiContainer is frozen"; + _logger.Error(errorMsg); + throw new InvalidOperationException(errorMsg); + } + } + + /// + /// 确保ServiceProvider已构建,如果未构建则抛出异常 + /// 用于保护获取服务操作的安全性 + /// + /// 当ServiceProvider未构建时抛出 + private void EnsureProvider() + { + if (_provider == null) + { + throw new InvalidOperationException( + "Container has not been frozen yet. Call Freeze() before retrieving services."); + } + } + + #endregion +} \ No newline at end of file