c#开发的ref和watch实现--轻松完成响应式开发--

2024-08-22 22:49:58 浏览数 (3)

代码语言:txt复制
using System;
using System.Collections.Generic;


public class Observable
{
    private readonly Dictionary<string, List<Action<object, object>>> _propertyObservers = new();

    public ObservableProperty<T> Ref<T>(T initialValue, string propertyName)
    {
        return new ObservableProperty<T>(initialValue, this, propertyName);
    }

    public ObservableList<T> RefList<T>(IList<T> initialValue, string propertyName)
    {
        var list = new ObservableList<T>(initialValue, this, propertyName);
        return list;
    }

    public void Watch(string propertyName, Action<object, object> callback)
    {
        if (!_propertyObservers.ContainsKey(propertyName))
        {
            _propertyObservers[propertyName] = new List<Action<object, object>>();
        }

        _propertyObservers[propertyName].Add(callback);
    }

    public void Unwatch(string propertyName, Action<object, object> callback)
    {
        if (_propertyObservers.ContainsKey(propertyName))
        {
            _propertyObservers[propertyName].Remove(callback);
        }
    }

    public void NotifyPropertyChange(string propertyName, object oldValue, object newValue)
    {
        if (_propertyObservers.TryGetValue(propertyName, out var callbacks))
        {
            foreach (var callback in callbacks)
            {
                callback?.Invoke(oldValue, newValue);
            }
        }
    }
}
复制
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

public class ObservableProperty<T>
{
    private T _value;
    private readonly Observable _observable;
    private readonly string _propertyName;

    public ObservableProperty(T initialValue, Observable observable, string propertyName)
    {
        _value = initialValue;
        _observable = observable;
        _propertyName = propertyName;
    }

    public string PropertyName => _propertyName;

    public T Value
    {
        get => _value;
        set
        {
            if (!EqualityComparer<T>.Default.Equals(_value, value))
            {
                T oldValue = _value;
                _value = value;
                _observable.NotifyPropertyChange(_propertyName, oldValue, value);
            }
        }
    }
}
public class ObservableList<T> : Collection<T>
{
    private readonly Observable _observable;
    private readonly string _propertyName;

    public ObservableList(IList<T> list, Observable observable, string propertyName)
        : base(list)
    {
        _observable = observable;
        _propertyName = propertyName;
    }

    protected override void InsertItem(int index, T item)
    {
        base.InsertItem(index, item);
        NotifyChange();
    }

    protected override void SetItem(int index, T item)
    {
        T oldItem = Items[index];
        base.SetItem(index, item);
        NotifyChange(oldItem, item);
    }

    protected override void RemoveItem(int index)
    {
        T item = Items[index];
        base.RemoveItem(index);
        NotifyChange(item, default(T)); // 使用 default(T) 来代表 null
    }

    protected override void ClearItems()
    {
        var oldItems = Items.ToList(); // 将 Items 转换为 List<T>
        base.ClearItems();
        NotifyChange(oldItems, new List<T>());
    }

    private void NotifyChange(T oldValue, T newValue)
    {
        _observable.NotifyPropertyChange(_propertyName, oldValue, newValue);
    }

    private void NotifyChange()
    {
        _observable.NotifyPropertyChange(_propertyName, null, null);
    }

    private void NotifyChange(List<T> oldValues, List<T> newValues)
    {
        _observable.NotifyPropertyChange(_propertyName, oldValues, newValues);
    }
}

使用方法:

代码语言:txt复制
public Observable _observable = new Observable();

对于只是监听对象的变化而不去关注某一项的变化的话可以使用如下方式:

代码语言:txt复制
    public ObservableProperty<string> Time { get; set; }
       public PlayerCompany()

    {

        Time = _observable.Ref("Initial Time", nameof(Time));

    }

我这段使用的是单例模式,所以用了一个构造函数,这样方便管理与维护

如果力邀使用较为特殊的情况,需要监听每一项值得变化得话你可以使用如下方式:

代码语言:txt复制
    public ObservableList<Employee> Mangers { get; set; }
    public PlayerCompany()

    {

        Mangers = _observable.RefList(new List<Employee> { null},nameof(Mangers));

    }

上面得方式是注册一个被观察对象放在观察列表中,那么下面将告诉你如何使用watch了。

代码语言:txt复制
 PlayerCompany.Instance._observable.Watch(nameof(PlayerCompany.Time), _timeChangeCallback = (oldValue, newValue) =>
 {

 });

这个watch提供了两个参数,第一个就是注册被观察对象得键值,第二个是一个回调函数,这个回调函数给定一个改版之前得值和改变之后的值。

如果是要关注每一项值的变化注册的被观察对象那么虽然使用的都是watch但是oldValue和newValue给的值并不是所有的值都给,而是哪一个值发生了改变哪一个值就会被单独拎出来通过oldValue和newValue返回新旧的值。

当然,考虑到性能问题,所以提供了Unwatch函数,就是用来随时关闭侦听的,性能问题就会根据使用场景而变化了。

0 人点赞