限制 BehaviorSubject 的值

Clamp the value of a BehaviorSubject

是否可以转换/验证 ISubject<T> 的值?

例如我有一个 BehaviorSubject<double> zoomFactor = new(1);,我想夹在 0.110 之间。

如何创建具有所需行为的自定义 ISubject<T> 实现?

class BehaviorTransformSubject<T> : ISubject<T>
{
    private readonly BehaviorSubject<T> _subject;
    private readonly Func<T, T> _transform;

    public BehaviorTransformSubject(T value, Func<T, T> transform)
    {
        _subject = new BehaviorSubject<T>(value);
        _transform = transform;
    }

    public void OnNext(T value) => _subject.OnNext(_transform(value));
    public void OnCompleted() => _subject.OnCompleted();
    public void OnError(Exception error) => _subject.OnError(error);
    public IDisposable Subscribe(IObserver<T> o) => _subject.Subscribe(o);
}

用法示例:

ISubject<double> zoomFactor = new BehaviorTransformSubject<double>(1.0,
    x => Math.Clamp(x, 0.1, 10.0));

替代实现: OnNext 方法可以这样替代实现:

public void OnNext(T value)
{
    T newValue;
    try { newValue = _transform(value); }
    catch (Exception ex) { _subject.OnError(ex); return; }
    _subject.OnNext(newValue);
}

这个函数以不同的方式处理 transform 函数可能出现的故障。它不会将错误直接抛回给调用 OnNext 方法的生产者,而是将错误传播给主题的消费者,从而导致其不可逆的终止(不再通过该主题传播任何值)。我想最初的 OnNext 实现具有您正在寻找的语义,但我可能错了。

公平地说,Math.Clamp 方法永远不会失败(根据文档),因此这种区别在您的案例中主要是学术性的。