feat(ioc): 实现IOC容器线程安全与冻结机制

- 添加读写锁确保多线程环境下的访问安全
- 引入冻结标志位防止容器被意外修改
- 注册和查询方法均增加锁保护逻辑
- 新增 Freeze 方法用于锁定容器状态
- 重构注册内部逻辑并提取公共方法
- 所有公开方法添加线程安全注释说明
- [not tag]
This commit is contained in:
GeWuYou 2025-12-18 09:26:13 +08:00
parent 5270a19e44
commit d924cba726
2 changed files with 168 additions and 46 deletions

View File

@ -46,6 +46,8 @@ public abstract class Architecture<T> : IArchitecture where T : Architecture<T>,
foreach (var system in arch._mSystems) system.Init();
arch._mSystems.Clear();
// 冻结IOC容器不允许 anymore
arch._mContainer.Freeze();
// 发送架构初始化完成事件
arch.SendEvent(new ArchitectureEvents.ArchitectureInitializedEvent());
arch._mInited = true;

View File

@ -13,6 +13,28 @@ public class IocContainer
/// </summary>
private readonly Dictionary<Type, List<object>> _instances = new();
#region Lock
/// <summary>
/// 读写锁对象,用于控制多线程环境下对共享资源的访问
/// 使用ReaderWriterLockSlim提供高效的读写锁定机制
/// 配置为不支持递归锁,避免死锁风险
/// </summary>
private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.NoRecursion);
#endregion
#region Flag
/// <summary>
/// 冻结标志位,用于标识对象是否已被冻结
/// true表示对象已冻结不可修改false表示对象可正常修改
/// </summary>
private bool _frozen;
#endregion
#region Register
/// <summary>
@ -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();
}
}
/// <summary>
/// 注册多个接口实现,并将其实例同时绑定到其所有匹配的接口上
/// 注册一个实例及其所有可赋值的接口类型到容器中
/// </summary>
/// <typeparam name="T">基类型或接口类型</typeparam>
/// <param name="instance">具体的实例对象</param>
/// <typeparam name="T">实例的类型</typeparam>
/// <param name="instance">要注册的实例对象不能为null</param>
public void RegisterPlurality<T>(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();
}
}
/// <summary>
/// 在内部字典中注册指定类型和实例的映射关系
/// </summary>
/// <param name="type">要注册的类型</param>
/// <param name="instance">要注册的实例</param>
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);
}
/// <summary>
/// 注册实例(自动支持多实例)
/// 注册指定类型的实例到容器中
/// </summary>
/// <typeparam name="T">要注册的实例类型</typeparam>
/// <param name="instance">要注册的实例</param>
/// <typeparam name="T">要注册的实例类型</typeparam>
/// <param name="instance">要注册的实例对象不能为null</param>
public void Register<T>(T instance)
{
Register(typeof(T), instance!);
// 获取写锁以确保线程安全
_lock.EnterWriteLock();
try
{
RegisterInternal(typeof(T), instance!);
}
finally
{
// 释放写锁
_lock.ExitWriteLock();
}
}
/// <summary>
/// 按指定类型注册实例
/// (常用于 interface / base type
/// 注册指定类型的实例到容器中
/// </summary>
/// <param name="type">要注册的目标类型</param>
/// <param name="instance">要注册的实例</param>
/// <param name="type">要注册的实例类型</param>
/// <param name="instance">要注册的实例对象</param>
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
/// <returns>找到的第一个实例;如果未找到则返回 null</returns>
public T? Get<T>() 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();
}
}
/// <summary>
/// 获取指定类型的必需实例
/// </summary>
@ -143,16 +225,20 @@ public class IocContainer
/// <returns>所有符合条件的实例列表;如果没有则返回空数组</returns>
public IReadOnlyList<T> GetAll<T>() where T : class
{
var type = typeof(T);
if (_instances.TryGetValue(type, out var list))
_lock.EnterReadLock();
try
{
return list.Cast<T>().ToList();
return _instances.TryGetValue(typeof(T), out var list)
? list.Cast<T>().ToList() // 快照
: Array.Empty<T>();
}
finally
{
_lock.ExitReadLock();
}
return Array.Empty<T>();
}
/// <summary>
/// 获取并排序(系统调度专用)
/// </summary>
@ -172,21 +258,55 @@ public class IocContainer
#region Utility
/// <summary>
/// 是否已注册指定类型
/// 检查容器中是否包含指定类型的实例
/// </summary>
/// <typeparam name="T">要检查是否注册的类型</typeparam>
/// <returns>若该类型已被注册则返回 true否则返回 false</returns>
/// <typeparam name="T">要检查的类型</typeparam>
/// <returns>如果容器中包含指定类型的实例则返回true否则返回false</returns>
public bool Contains<T>()
{
return _instances.ContainsKey(typeof(T));
_lock.EnterReadLock();
try
{
return _instances.ContainsKey(typeof(T));
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// 清空容器
/// 清空容器中的所有实例
/// </summary>
public void Clear()
{
_instances.Clear();
// 获取写锁以确保线程安全的清空操作
_lock.EnterWriteLock();
try
{
_instances.Clear();
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// 冻结容器,防止后续修改
/// </summary>
public void Freeze()
{
// 获取写锁以确保线程安全的状态修改
_lock.EnterWriteLock();
try
{
_frozen = true;
}
finally
{
_lock.ExitWriteLock();
}
}
#endregion