GFramework/GFramework.Core/property/BindableProperty.cs
GeWuYou f984f4a600 refactor(core): 优化核心组件的线程安全性和错误处理
- 重构 AsyncLogAppender 的 Flush 方法,添加超时控制和 SpinWait 优化
- 为 BindableProperty 添加线程安全锁保护,确保并发访问的安全性
- 在 BindableProperty 中实现回调外部调用以避免死锁问题
- 为 EasyEvents 使用 ConcurrentDictionary 替代 Dictionary 提高并发性能
- 添加协程调度器异常处理回调机制,防止异常传播导致调度器崩溃
- 为 FileAppender 添加初始化异常处理和资源清理逻辑
- 补充完整的单元测试覆盖并发场景下的线程安全性验证
2026-03-04 11:04:59 +08:00

169 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using GFramework.Core.Abstractions.events;
using GFramework.Core.Abstractions.property;
namespace GFramework.Core.property;
/// <summary>
/// 可绑定属性类,用于实现数据绑定功能
/// 线程安全:所有公共方法都是线程安全的
/// </summary>
/// <typeparam name="T">属性值的类型</typeparam>
/// <param name="defaultValue">属性的默认值</param>
public class BindableProperty<T>(T defaultValue = default!) : IBindableProperty<T>
{
/// <summary>
/// 用于保护委托链和值访问的锁对象
/// </summary>
private readonly object _lock = new();
/// <summary>
/// 属性值变化事件回调委托,当属性值发生变化时被调用
/// </summary>
private Action<T>? _mOnValueChanged;
/// <summary>
/// 存储属性实际值的受保护字段
/// </summary>
protected T MValue = defaultValue;
/// <summary>
/// 获取或设置属性值比较器默认使用Equals方法进行比较
/// </summary>
public static Func<T, T, bool> Comparer { get; set; } = (a, b) => a!.Equals(b);
/// <summary>
/// 获取或设置属性值,当值发生变化时会触发注册的回调事件
/// </summary>
public T Value
{
get => GetValue();
set
{
Action<T>? callback = null;
lock (_lock)
{
// 使用 default(T) 替代 null 比较,避免 SonarQube 警告
if (EqualityComparer<T>.Default.Equals(value, default!) &&
EqualityComparer<T>.Default.Equals(MValue, default!))
return;
// 若新值与旧值相等则不执行后续操作
if (!EqualityComparer<T>.Default.Equals(value, default!) && Comparer(value, MValue))
return;
SetValue(value);
callback = _mOnValueChanged;
}
// 在锁外调用回调,避免死锁
callback?.Invoke(value);
}
}
/// <summary>
/// 直接设置属性值而不触发事件
/// </summary>
/// <param name="newValue">新的属性值</param>
public void SetValueWithoutEvent(T newValue)
{
MValue = newValue;
}
/// <summary>
/// 实现IEasyEvent接口的注册方法将无参事件转换为有参事件处理
/// </summary>
/// <param name="onEvent">无参事件回调</param>
/// <returns>可用于取消注册的接口</returns>
IUnRegister IEvent.Register(Action onEvent)
{
return Register(Action);
void Action(T _)
{
onEvent();
}
}
/// <summary>
/// 注册属性值变化事件回调
/// </summary>
/// <param name="onValueChanged">属性值变化时的回调函数</param>
/// <returns>可用于取消注册的接口</returns>
public IUnRegister Register(Action<T> onValueChanged)
{
lock (_lock)
{
_mOnValueChanged += onValueChanged;
}
return new BindablePropertyUnRegister<T>(this, onValueChanged);
}
/// <summary>
/// 注册属性值变化事件回调,并立即调用回调函数传递当前值
/// </summary>
/// <param name="action">属性值变化时的回调函数</param>
/// <returns>可用于取消注册的接口</returns>
public IUnRegister RegisterWithInitValue(Action<T> action)
{
T currentValue;
lock (_lock)
{
currentValue = MValue;
}
action(currentValue);
return Register(action);
}
/// <summary>
/// 取消注册属性值变化事件回调
/// </summary>
/// <param name="onValueChanged">要取消注册的回调函数</param>
public void UnRegister(Action<T> onValueChanged)
{
lock (_lock)
{
_mOnValueChanged -= onValueChanged;
}
}
/// <summary>
/// 设置自定义比较器
/// </summary>
/// <param name="comparer">用于比较两个值是否相等的函数</param>
/// <returns>当前可绑定属性实例</returns>
public BindableProperty<T> WithComparer(Func<T, T, bool> comparer)
{
Comparer = comparer;
return this;
}
/// <summary>
/// 设置属性值的虚方法,可在子类中重写
/// </summary>
/// <param name="newValue">新的属性值</param>
protected virtual void SetValue(T newValue)
{
MValue = newValue;
}
/// <summary>
/// 获取属性值的虚方法,可在子类中重写
/// </summary>
/// <returns>当前属性值</returns>
protected virtual T GetValue()
{
return MValue;
}
/// <summary>
/// 返回属性值的字符串表示形式
/// </summary>
/// <returns>属性值的字符串表示</returns>
public override string ToString()
{
return Value?.ToString() ?? string.Empty;
}
}