From d924cba7265b924a77e9bb55f5a1c77239bc0c26 Mon Sep 17 00:00:00 2001 From: GeWuYou <95328647+GeWuYou@users.noreply.github.com> Date: Thu, 18 Dec 2025 09:26:13 +0800 Subject: [PATCH] =?UTF-8?q?feat(ioc):=20=E5=AE=9E=E7=8E=B0IOC=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=E7=BA=BF=E7=A8=8B=E5=AE=89=E5=85=A8=E4=B8=8E=E5=86=BB?= =?UTF-8?q?=E7=BB=93=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加读写锁确保多线程环境下的访问安全 - 引入冻结标志位防止容器被意外修改 - 注册和查询方法均增加锁保护逻辑 - 新增 Freeze 方法用于锁定容器状态 - 重构注册内部逻辑并提取公共方法 - 所有公开方法添加线程安全注释说明 - [not tag] --- GFramework.Core/architecture/Architecture.cs | 2 + GFramework.Core/ioc/IocContainer.cs | 212 +++++++++++++++---- 2 files changed, 168 insertions(+), 46 deletions(-) diff --git a/GFramework.Core/architecture/Architecture.cs b/GFramework.Core/architecture/Architecture.cs index 4357437..ccf779c 100644 --- a/GFramework.Core/architecture/Architecture.cs +++ b/GFramework.Core/architecture/Architecture.cs @@ -46,6 +46,8 @@ public abstract class Architecture : IArchitecture where T : Architecture, foreach (var system in arch._mSystems) system.Init(); arch._mSystems.Clear(); + // 冻结IOC容器,不允许 anymore + arch._mContainer.Freeze(); // 发送架构初始化完成事件 arch.SendEvent(new ArchitectureEvents.ArchitectureInitializedEvent()); arch._mInited = true; diff --git a/GFramework.Core/ioc/IocContainer.cs b/GFramework.Core/ioc/IocContainer.cs index 1ec53d6..fe10d91 100644 --- a/GFramework.Core/ioc/IocContainer.cs +++ b/GFramework.Core/ioc/IocContainer.cs @@ -13,6 +13,28 @@ public class IocContainer /// private readonly Dictionary> _instances = new(); + #region Lock + + /// + /// 读写锁对象,用于控制多线程环境下对共享资源的访问 + /// 使用ReaderWriterLockSlim提供高效的读写锁定机制 + /// 配置为不支持递归锁,避免死锁风险 + /// + private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.NoRecursion); + + #endregion + + #region Flag + + /// + /// 冻结标志位,用于标识对象是否已被冻结 + /// true表示对象已冻结,不可修改;false表示对象可正常修改 + /// + private bool _frozen; + + #endregion + + #region Register /// @@ -26,30 +48,74 @@ public class IocContainer { var type = typeof(T); - if (_instances.TryGetValue(type, out var list) && list.Count > 0) + _lock.EnterWriteLock(); + try { - throw new InvalidOperationException( - $"Singleton already registered for type: {type.Name}"); - } + if (_instances.TryGetValue(type, out var list) && list.Count > 0) + { + throw new InvalidOperationException( + $"Singleton already registered for type: {type.Name}"); + } - _instances[type] = [instance!]; + _instances[type] = [instance!]; + } + finally + { + _lock.ExitWriteLock(); + } } + /// - /// 注册多个接口实现,并将其实例同时绑定到其所有匹配的接口上 + /// 注册一个实例及其所有可赋值的接口类型到容器中 /// - /// 基类型或接口类型 - /// 具体的实例对象 + /// 实例的类型 + /// 要注册的实例对象,不能为null public void RegisterPlurality(T instance) { var concreteType = instance!.GetType(); - Register(concreteType, instance); - // 获取实例类型实现的所有接口,并筛选出可以赋值给T类型的接口 + // 获取实例类型直接实现的所有接口,并筛选出可以赋值给T类型的接口 var interfaces = concreteType.GetInterfaces() .Where(typeof(T).IsAssignableFrom); - foreach (var itf in interfaces) + + _lock.EnterWriteLock(); + try { - Register(itf, instance); + // 注册具体类型 + RegisterInternal(concreteType, instance); + + // 注册所有匹配的接口类型 + foreach (var itf in interfaces) + { + RegisterInternal(itf, instance); + } + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// + /// 在内部字典中注册指定类型和实例的映射关系 + /// + /// 要注册的类型 + /// 要注册的实例 + private void RegisterInternal(Type type, object instance) + { + if (_frozen) + throw new InvalidOperationException("IocContainer is frozen"); + // 如果该类型还没有对应的实例列表,则创建一个新的列表 + if (!_instances.TryGetValue(type, out var list)) + { + list = []; + _instances[type] = list; + } + + // 避免重复添加相同的实例 + if (!list.Contains(instance)) + { + list.Add(instance); } } @@ -62,34 +128,44 @@ public class IocContainer RegisterPlurality(system); } + /// - /// 注册实例(自动支持多实例) + /// 注册指定类型的实例到容器中 /// - /// 要注册的实例的类型 - /// 要注册的实例 + /// 要注册的实例类型 + /// 要注册的实例对象,不能为null public void Register(T instance) { - Register(typeof(T), instance!); + // 获取写锁以确保线程安全 + _lock.EnterWriteLock(); + try + { + RegisterInternal(typeof(T), instance!); + } + finally + { + // 释放写锁 + _lock.ExitWriteLock(); + } } /// - /// 按指定类型注册实例 - /// (常用于 interface / base type) + /// 注册指定类型的实例到容器中 /// - /// 要注册的目标类型 - /// 要注册的实例 + /// 要注册的实例类型 + /// 要注册的实例对象 public void Register(Type type, object instance) { - if (!_instances.TryGetValue(type, out var list)) + // 获取写锁以确保线程安全 + _lock.EnterWriteLock(); + try { - list = []; - _instances[type] = list; + RegisterInternal(type, instance); } - - // 防止重复注册同一个实例 - if (!list.Contains(instance)) + finally { - list.Add(instance); + // 释放写锁 + _lock.ExitWriteLock(); } } @@ -105,17 +181,23 @@ public class IocContainer /// 找到的第一个实例;如果未找到则返回 null public T? Get() where T : class { - var type = typeof(T); - - // 尝试从实例字典中获取指定类型的实例列表 - if (_instances.TryGetValue(type, out var list) && list.Count > 0) + _lock.EnterReadLock(); + try { - return list[0] as T; - } + if (_instances.TryGetValue(typeof(T), out var list) && list.Count > 0) + { + return list[0] as T; + } - return null; + return null; + } + finally + { + _lock.ExitReadLock(); + } } + /// /// 获取指定类型的必需实例 /// @@ -143,16 +225,20 @@ public class IocContainer /// 所有符合条件的实例列表;如果没有则返回空数组 public IReadOnlyList GetAll() where T : class { - var type = typeof(T); - - if (_instances.TryGetValue(type, out var list)) + _lock.EnterReadLock(); + try { - return list.Cast().ToList(); + return _instances.TryGetValue(typeof(T), out var list) + ? list.Cast().ToList() // 快照 + : Array.Empty(); + } + finally + { + _lock.ExitReadLock(); } - - return Array.Empty(); } + /// /// 获取并排序(系统调度专用) /// @@ -172,21 +258,55 @@ public class IocContainer #region Utility /// - /// 是否已注册指定类型 + /// 检查容器中是否包含指定类型的实例 /// - /// 要检查是否注册的类型 - /// 若该类型已被注册则返回 true,否则返回 false + /// 要检查的类型 + /// 如果容器中包含指定类型的实例则返回true,否则返回false public bool Contains() { - return _instances.ContainsKey(typeof(T)); + _lock.EnterReadLock(); + try + { + return _instances.ContainsKey(typeof(T)); + } + finally + { + _lock.ExitReadLock(); + } } /// - /// 清空容器 + /// 清空容器中的所有实例 /// public void Clear() { - _instances.Clear(); + // 获取写锁以确保线程安全的清空操作 + _lock.EnterWriteLock(); + try + { + _instances.Clear(); + } + finally + { + _lock.ExitWriteLock(); + } + } + + /// + /// 冻结容器,防止后续修改 + /// + public void Freeze() + { + // 获取写锁以确保线程安全的状态修改 + _lock.EnterWriteLock(); + try + { + _frozen = true; + } + finally + { + _lock.ExitWriteLock(); + } } #endregion