首页 > 解决方案 > 限制 BehaviorSubject 的值

问题描述

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

例如,我有一个BehaviorSubject<double> zoomFactor = new(1);我想被夹在0.1和之间10

标签: c#.netsystem.reactivereactivexrx.net

解决方案


如何创建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方法永远不会失败(根据文档),因此在您的情况下,这种区别主要是学术性的。


推荐阅读