using GFramework.Core.system;
namespace GFramework.Core.ioc;
///
/// IOC容器类,用于管理对象的注册和获取
///
public class IocContainer
{
///
/// 核心存储结构:
/// 一个 Type 对应 0~N 个实例
///
private readonly Dictionary> _instances = new();
#region Lock
///
/// 读写锁对象,用于控制多线程环境下对共享资源的访问
/// 使用ReaderWriterLockSlim提供高效的读写锁定机制
/// 配置为不支持递归锁,避免死锁风险
///
private readonly ReaderWriterLockSlim _lock = new(LockRecursionPolicy.NoRecursion);
#endregion
#region Flag
///
/// 冻结标志位,用于标识对象是否已被冻结
/// true表示对象已冻结,不可修改;false表示对象可正常修改
///
private volatile bool _frozen;
#endregion
#region Register
///
/// 注册单例(强语义)
/// 一个类型只允许一个实例
///
/// 要注册为单例的类型
/// 要注册的单例实例
/// 当该类型已经注册过单例时抛出异常
public void RegisterSingleton(T instance)
{
var type = typeof(T);
_lock.EnterWriteLock();
try
{
if (_instances.TryGetValue(type, out var list) && list.Count > 0)
{
throw new InvalidOperationException(
$"Singleton already registered for type: {type.Name}");
}
_instances[type] = [instance!];
}
finally
{
_lock.ExitWriteLock();
}
}
///
/// 注册一个实例及其所有可赋值的接口类型到容器中
///
/// 实例的类型
/// 要注册的实例对象,不能为null
public void RegisterPlurality(T instance)
{
var concreteType = instance!.GetType();
// 获取实例类型直接实现的所有接口,并筛选出可以赋值给T类型的接口
var interfaces = concreteType.GetInterfaces()
.Where(typeof(T).IsAssignableFrom);
_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)
throw new InvalidOperationException("IocContainer is frozen");
// 如果该类型还没有对应的实例列表,则创建一个新的列表
if (!_instances.TryGetValue(type, out var list))
{
list = [];
_instances[type] = list;
}
// 避免重复添加相同的实例
if (!list.Contains(instance))
{
list.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 (_instances.TryGetValue(typeof(T), out var list) && list.Count > 0)
{
return list[0] as T;
}
return null;
}
finally
{
_lock.ExitReadLock();
}
}
///
/// 获取指定类型的必需实例
///
/// 期望获取的实例类型
/// 找到的唯一实例
/// 当没有注册实例或注册了多个实例时抛出
public T GetRequired() where T : class
{
var list = GetAll();
// 根据实例数量进行判断和处理
return list.Count switch
{
0 => throw new InvalidOperationException($"No instance registered for {typeof(T).Name}"),
> 1 => throw new InvalidOperationException($"Multiple instances registered for {typeof(T).Name}"),
_ => list[0]
};
}
///
/// 获取指定类型的所有实例(接口 / 抽象类推荐使用)
///
/// 期望获取的实例类型
/// 所有符合条件的实例列表;如果没有则返回空数组
public IReadOnlyList GetAll() where T : class
{
_lock.EnterReadLock();
try
{
return _instances.TryGetValue(typeof(T), out var list)
? list.Cast().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 _instances.ContainsKey(typeof(T));
}
finally
{
_lock.ExitReadLock();
}
}
///
/// 清空容器中的所有实例
///
public void Clear()
{
// 获取写锁以确保线程安全的清空操作
_lock.EnterWriteLock();
try
{
_instances.Clear();
}
finally
{
_lock.ExitWriteLock();
}
}
///
/// 冻结容器,防止后续修改
///
public void Freeze()
{
// 获取写锁以确保线程安全的状态修改
_lock.EnterWriteLock();
try
{
_frozen = true;
}
finally
{
_lock.ExitWriteLock();
}
}
#endregion
}