【问题标题】:How to combine "IObservable<bool> IsActive" and "bool IsEnabled" in one subsciption如何在一个订阅中结合“IObservable<bool> IsActive”和“bool IsEnabled”
【发布时间】:2020-02-20 23:10:44
【问题描述】:

有两个属性,一个是public IObservable&lt;bool&gt; IsEnabled { get; set; } 类型,第二个是public bool IsActive { get;set; },我想使用System.Reactive 将这两个属性合二为一,就像public bool IsActiveAndEnabled {get;set;} 一样

public class BindableProperty<T> 
{
    T Value { get; }
}

public class Manager
{
    public IObservable<bool> IsEnabled { get; set; }

    public BindableProperty<bool> IsActiveAndEnabled { get; set; }


    private bool isActive;
    public bool IsActive
    {
        get { return isActive; }
        set
        {
            isActive = value;
            // Call OnPropertyChanged whenever the property is updated
            OnPropertyChanged(() => IsActive);
        }
    }

    private void OnPropertyChanged(Func<bool> property)
    {
        throw new NotImplementedException();
    }

    public Manager()
    {
        IsEnabled
            .And(/* accept only observable, but I want to join with IsActive*/)
            .Then((isEnabled,isActive) => IsActiveAndEnabled = isEnabled && isActive);
    }
}

【问题讨论】:

  • 听起来是一个有价值的目标。你被困在哪里了?您能否向我们展示您的实际代码,而不仅仅是少数属性签名?
  • 你卡在哪里了?
  • 嗨@Enigmativity,我提供了更多信息,希望我很清楚。
  • 您确定要在 IObservable&lt;T&gt; 中放置一个标量值而不是主题类型吗?
  • 不清楚BindableProperty&lt;T&gt; 是什么或如何更新它,所以我只假设public bool IsActiveAndEnabled { get; private set; } 形式的普通属性。在那种情况下,IsEnabled.StartWith(true).Subscribe(isEnabled =&gt; IsActiveAndEnabled = isEnabled &amp;&amp; isActive); 对你有用吗?

标签: c# reactive-programming system.reactive rx.net


【解决方案1】:
  • 您发布的代码并不是如何使用反应式编程范例的好例子。

    • 请不要将“Observable”视为可变 对象类的单个标量值成员属性的视图。
      • 我责怪微软让人们产生了这种误解,因为他们在很久以前就将 ObservableCollection 添加到 .NET Framework 中,但是他们在 ObservableCollection 的上下文中(错误)使用“可观察”一词与含义完全无关Observable 的反应式编程。
  • 在进行响应式编程时,Observable 是数据对象流的源(或发射器)(请注意,流可以为空(从不发射任何东西)或只发射一个对象在它自己关闭之前,或者每秒发出数千个对象)。

  • 因此,IObservable 最好被视为“IEnumerable&lt;T&gt;-that-pushes”(与具有“拉”语义的普通 IEnumerable&lt;T&gt; 相比)。
  • 另一个重要的事情是 Observable 发出的对象应该(不,必须)是不可变的! - 或者至少,发出的对象不能与任何其他发出的对象共享可变状态!
    • 这是因为如果一个值随着时间而改变 - 或者如果写入一个对象的更改会影响其他对象 - 那么使用返回对象的不同实例的程序的其他部分将在他们不期望的情况下改变其状态.

我强烈建议您先阅读有关反应式编程概念的指南或教程,然后再继续下一步。大多数指南和教程都涵盖了 RxJS(Reactive Extensions for JavaScript,在 Angular 决定使用 Observable&lt;Response&gt; 而不是 Promise&lt;Response&gt; 作为其内置 HTTP 客户端库之后填充。虽然许多指南涵盖 RxJS,但它们完全适用于 Reactive为其他平台编程,例如 .NET(虽然 IObservable&lt;T&gt; 是 .NET Framework 的一部分,但您需要单独的 Reactive Extensions 库才能正确地进行响应式编程,而无需重新发明轮子)。

重要提示:Reactive Extensions, RxJS and Reactive programming have absolutely nothing to do with "React"/"ReactJS" and the React-pattern(有切线关系,但它们是完全不同的东西)。

资源:

至于你的情况,这是我的建议:

如果class Manager 必须是可变的:

  • 删除public IObservable&lt;bool&gt; IsEnabled { get; set; }
  • 定义一个新的不可变class ManagerState
  • 扩展class Manager : IObservable&lt;ManagerState&gt;
  • 每当class Manager 中的可变属性发生更改时,都会向订阅者发送一个新的ManagerState(填充Manager 的快照副本)。

如果class Manager 可以设为不可变:

  • 删除public IObservable&lt;bool&gt; IsEnabled { get; set; }
  • 定义一个实现IObservable&lt;Manager&gt;的新类ManagerSource
  • 每次Manager 以某种方式更新时,都会向订阅者发送一个新的Manager 对象(填充Manager 的快照副本)。

示例(当class Manager 可变时):

class Manager : IObservable<ManagerState>
{
    private Boolean isEnabled; // backing field
    public Boolean IsEnabled
    {
        get { return this.isEnabled; }
        set
        {
            this.isEnabled = value;
            this.NotifySubscribers();
        }
    }

    private Boolean isActive; // backing field
    public Boolean IsActive
    {
        get { return this.isActive; }
        set
        {
            this.isActive = value;
            this.NotifySubscribers();
        }
    }

    #region Observers (Subscribers) handling:

    private readonly ConcurrentBag<IObserver<ManagerState>> subscribers = new ConcurrentBag<IObserver<ManagerState>>();

    private void NotifySubscribers()
    {
        ManagerState snapshot = new ManagerState(
            this.IsEnabled,
            this.IsActive,
            // etc
        );

        foreach( IObserver<ManagerState> observer in this.subscribers )
        {
            observer.OnNext( snapshot );
        } 
    }

    #endregion
}

// Represents a snapshot of the state of a `Manager`
class ManagerState
{
    public ManagerState( Boolean isEnabled, Boolean isActive )
    {
        this.IsEnabled = isEnabled;
        this.IsActive  = isActive;
    }

    public Boolean IsEnabled { get; }
    public Boolean IsActive  { get; }
    // any other members, etc
}

请注意,这可以与对INotifyPropertyChanged 的支持结合使用(尽管我认为这是一个坏主意,因为支持多种方式来完成同一件事最终会使您的用户感到困惑/消费者/同事)——有点像System.Net.Sockets.SocketAcceptAcceptAsyncBeginAccept/EndAccept,因为它支持同步,以及 APM 和 EAP 异步范式(但由于某种原因不支持 TPL)。

class Manager : IObservable<ManagerState>, INotifyPropertyChanged
{
    private Boolean isEnabled; // backing field
    public Boolean IsEnabled
    {
        get { return this.isEnabled; }
        set
        {
            this.isEnabled = value;
            this.OnPropertyChanged( nameof(this.IsEnabled) );
        }
    }

    private Boolean isActive; // backing field
    public Boolean IsActive
    {
        get { return this.isActive; }
        set
        {
            this.isActive = value;
            this.OnPropertyChanged( nameof(this.IsActive) );
        }
    }

    #region INotifyPropetyChanged and Observers (Subscribers) handling:

    private readonly ConcurrentBag<IObserver<ManagerState>> subscribers = new ConcurrentBag<IObserver<ManagerState>>();

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged( String name )
    {
        // First, notify users of INotifyPropetyChanged:

        this.PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( name ) );

        // Then notify users of IObservable:

        ManagerState snapshot = new ManagerState(
            this.IsEnabled,
            this.IsActive,
            // etc
        );

        foreach( IObserver<ManagerState> observer in this.subscribers )
        {
            observer.OnNext( snapshot );
        } 
    }

    #endregion
}

【讨论】:

  • 是的,我认为 MS 引入 IAsyncEnumerable 使事情更加混乱,在我看来,IAsyncEnumerable 试图实现与可观察流相同的目的,但具有异步延续。
  • @Frank imho IAsyncEnumerable 很好理解。
  • @Asti 我觉得IAsyncEnumerable虽然可以理解,但在概念上和IObservable是一样的
  • 让我们同意不同意 :) 我同意的一件事是,先生,您是学者和绅士。
  • 我唯一的遗憾是我只有一张赞成票可以给。 (:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多