using GFramework.Core.Abstractions.Events; using GFramework.Core.Abstractions.Property; using GFramework.Core.Abstractions.StateManagement; using GFramework.Core.Events; namespace GFramework.Core.StateManagement; /// /// Store 选择结果的只读绑定视图。 /// 该类型将整棵状态树上的订阅转换为局部状态片段的订阅, /// 使现有依赖 IReadonlyBindableProperty 的 UI 代码能够平滑复用到 Store 场景中。 /// /// 源状态类型。 /// 投影后的局部状态类型。 public sealed class StoreSelection : IReadonlyBindableProperty { /// /// 用于判断选择结果是否真正变化的比较器。 /// private readonly IEqualityComparer _comparer; /// /// 当前监听器列表。 /// private readonly List _listeners = []; /// /// 保护监听器集合和底层 Store 订阅句柄的同步锁。 /// private readonly object _lock = new(); /// /// 负责从完整状态中投影出局部状态的选择器。 /// private readonly Func _selector; /// /// 源 Store。 /// private readonly IReadonlyStore _store; /// /// 当前已缓存的选择结果。 /// 该缓存仅在存在监听器时用于变化比较和事件通知,直接读取 Value 时始终以 Store 当前状态为准。 /// private TSelected _currentValue = default!; /// /// 连接到底层 Store 的订阅句柄。 /// 仅当当前存在至少一个监听器时才会建立该订阅,以减少长期闲置对象造成的引用链。 /// private IUnRegister? _storeSubscription; /// /// 初始化一个新的 Store 选择视图。 /// /// 源 Store。 /// 状态选择器。 /// 选择结果比较器;未提供时使用 。 /// /// 当 时抛出。 /// public StoreSelection( IReadonlyStore store, Func selector, IEqualityComparer? comparer = null) { _store = store ?? throw new ArgumentNullException(nameof(store)); _selector = selector ?? throw new ArgumentNullException(nameof(selector)); _comparer = comparer ?? EqualityComparer.Default; } /// /// 获取当前选择结果。 /// public TSelected Value => _selector(_store.State); /// /// 将无参事件监听适配为带选择结果参数的监听。 /// /// 无参事件监听器。 /// 用于取消订阅的句柄。 IUnRegister IEvent.Register(Action onEvent) { ArgumentNullException.ThrowIfNull(onEvent); return Register(_ => onEvent()); } /// /// 注册选择结果变化监听器。 /// /// 选择结果变化时的回调。 /// 用于取消订阅的句柄。 /// 时抛出。 public IUnRegister Register(Action onValueChanged) { ArgumentNullException.ThrowIfNull(onValueChanged); var subscription = new SelectionListenerSubscription(onValueChanged); var shouldAttach = false; lock (_lock) { if (_listeners.Count == 0) { _currentValue = Value; shouldAttach = true; } _listeners.Add(subscription); } if (shouldAttach) { AttachToStore(); } return new DefaultUnRegister(() => UnRegister(subscription)); } /// /// 注册选择结果变化监听器,并立即回放当前值。 /// /// 选择结果变化时的回调。 /// 用于取消订阅的句柄。 /// 时抛出。 public IUnRegister RegisterWithInitValue(Action action) { ArgumentNullException.ThrowIfNull(action); var subscription = new SelectionListenerSubscription(action) { IsActive = false }; var currentValue = Value; TSelected? pendingValue = default; var hasPendingValue = false; lock (_lock) { if (_listeners.Count == 0) { _currentValue = currentValue; } _listeners.Add(subscription); } EnsureAttached(); try { action(currentValue); } catch { UnRegister(subscription); throw; } lock (_lock) { if (!subscription.IsSubscribed) { return new DefaultUnRegister(() => { }); } subscription.IsActive = true; if (subscription.HasPendingValue) { pendingValue = subscription.PendingValue; hasPendingValue = true; subscription.PendingValue = default!; subscription.HasPendingValue = false; } } if (hasPendingValue) { action(pendingValue!); } return new DefaultUnRegister(() => UnRegister(subscription)); } /// /// 取消注册选择结果变化监听器。 /// /// 需要移除的监听器。 /// 时抛出。 public void UnRegister(Action onValueChanged) { ArgumentNullException.ThrowIfNull(onValueChanged); SelectionListenerSubscription? subscriptionToRemove = null; lock (_lock) { var index = _listeners.FindIndex(subscription => subscription.Listener == onValueChanged); if (index < 0) { return; } subscriptionToRemove = _listeners[index]; } if (subscriptionToRemove != null) { UnRegister(subscriptionToRemove); } } /// /// 确保当前选择视图已连接到底层 Store。 /// private void EnsureAttached() { var shouldAttach = false; lock (_lock) { shouldAttach = _listeners.Count > 0 && _storeSubscription == null; } if (shouldAttach) { AttachToStore(); } } /// /// 取消注册一个精确的选择结果监听器。 /// /// 需要移除的订阅对象。 private void UnRegister(SelectionListenerSubscription subscriptionToRemove) { IUnRegister? storeSubscription = null; lock (_lock) { subscriptionToRemove.IsSubscribed = false; _listeners.Remove(subscriptionToRemove); if (_listeners.Count == 0 && _storeSubscription != null) { storeSubscription = _storeSubscription; _storeSubscription = null; } } storeSubscription?.UnRegister(); } /// /// 将当前选择视图连接到底层 Store。 /// private void AttachToStore() { var subscription = _store.Subscribe(OnStoreChanged); Action[] listenersSnapshot = Array.Empty>(); var latestValue = Value; var shouldNotify = false; lock (_lock) { // 如果在建立底层订阅期间所有监听器都已被移除,则立即释放刚刚建立的订阅, // 避免选择视图在无人监听时继续被 Store 保持引用。 if (_listeners.Count == 0) { subscription.UnRegister(); return; } if (_storeSubscription != null) { subscription.UnRegister(); return; } _storeSubscription = subscription; if (!_comparer.Equals(_currentValue, latestValue)) { _currentValue = latestValue; foreach (var listener in _listeners) { if (!listener.IsSubscribed) { continue; } if (listener.IsActive) { continue; } listener.PendingValue = latestValue; listener.HasPendingValue = true; } listenersSnapshot = _listeners .Where(listener => listener.IsSubscribed && listener.IsActive) .Select(listener => listener.Listener) .ToArray(); shouldNotify = listenersSnapshot.Length > 0; } } if (!shouldNotify) { return; } foreach (var listener in listenersSnapshot) { listener(latestValue); } } /// /// 响应底层 Store 的状态变化,并在选中片段真正变化时通知监听器。 /// /// 新的完整状态。 private void OnStoreChanged(TState state) { var selectedValue = _selector(state); Action[] listenersSnapshot = Array.Empty>(); lock (_lock) { if (_listeners.Count == 0 || _comparer.Equals(_currentValue, selectedValue)) { return; } _currentValue = selectedValue; foreach (var listener in _listeners) { if (!listener.IsSubscribed) { continue; } if (listener.IsActive) { continue; } listener.PendingValue = selectedValue; listener.HasPendingValue = true; } listenersSnapshot = _listeners .Where(listener => listener.IsSubscribed && listener.IsActive) .Select(listener => listener.Listener) .ToArray(); } foreach (var listener in listenersSnapshot) { listener(selectedValue); } } /// /// 表示一个选择结果监听订阅。 /// 该对象用于保证 RegisterWithInitValue 在初始化回放与后续状态变化之间不会漏掉最近一次更新。 /// private sealed class SelectionListenerSubscription(Action listener) { /// /// 获取订阅回调。 /// public Action Listener { get; } = listener; /// /// 获取或设置订阅是否已激活。 /// public bool IsActive { get; set; } = true; /// /// 获取或设置订阅是否仍然有效。 /// public bool IsSubscribed { get; set; } = true; /// /// 获取或设置是否存在待补发的局部状态值。 /// public bool HasPendingValue { get; set; } /// /// 获取或设置初始化阶段积累的最新局部状态值。 /// public TSelected PendingValue { get; set; } = default!; } }