【问题标题】:Clamp the value of a BehaviorSubject限制 BehaviorSubject 的值
【发布时间】:2021-08-14 14:22:35
【问题描述】:

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

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

  • 应该可以调用zoomFactor.OnNext(Math.Clamp(newZoomFactor, 0.1, 10)),但这样做会将责任推给调用者,我希望避免这种情况。
  • 我可以使用zoomFactor.Select(newZoomFactor => Math.Clamp(newZoomFactor, 0.1, 10)) 在观察后进行转换,但是:
    • 这是再次将责任外包给另一个调用者;
    • 原始的zoomFactor 值不会在此处更改:想象用户缩小超过限制并重新放大,但在实际值静默返回时,渲染的缩放仍停留在10内部的钳位边界...

【问题讨论】:

  • 是的,您可以使用.Select 转换主题的值。这就是它的用途。

标签: c# .net system.reactive reactivex rx.net


【解决方案1】:

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 2018-08-31
  • 2018-05-04
  • 2019-01-19
相关资源
最近更新 更多