如何在一个订阅中组合“ IObservable IsActive”和“ bool IsEnabled”

问题描述 投票:1回答:1

具有两个属性,其中一个类型为public IObservable<bool> 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);
    }
}
c# reactive-programming system.reactive rx.net
1个回答
1
投票
  • 您发布的代码不是如何使用反应式编程范例的好例子。

    • 请不要将“可观察的”视为对mutable类的单个标量值成员属性的视图。
      • [我怪微软引起人们的这种误解是因为他们早在.NET Framework中就添加了ObservableCollection,但在ObservableCollection上下文中对(可观察到的)术语的(误用)完全与无功编程中的Observable
  • 进行响应式编程时,一个Observable是数据对象流的源(或发射器)(请注意,流[[can为空(从不发出任何东西))或仅在其之前发出一个对象关闭自己,或每秒发出数千个对象)。

  • 因此,最好将IObservable视为“ IEnumerable<T>-推”(与具有[pull]语义的普通IEnumerable<T>相比。]]
  • 另一个重要的事情是,一个Observable发出的对象应该(不
  • 必须
  • )是不可变的! -或至少,所发射的对象不得与任何其他所发射的对象共享可变状态!
      这是因为如果值随时间变化-或如果将更改写入一个对象会影响其他对象-则程序的其他部分使用返回的对象的不同实例时,它们的状态将发生突变,而他们并不期望这样做。
  • 我强烈建议您遵循有关响应式编程概念的指南或教程,然后再继续进行。大多数指南和教程都涵盖了RxJS(JavaScript的反应式扩展,在Angular决定为其内置的HTTP客户端librar使用Observable<Response>而不是Promise<Response>之后进行填充。而许多指南都涉及RxJS,它们完全适用于Reactive .NET等其他平台的编程(IObservable<T>是.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<bool> IsEnabled { get; set; }

  • 定义新的
  • 不可变
  • class ManagerState扩展class Manager : IObservable<ManagerState>
  • 每次class Manager中的可变属性更改时,向订户发射一个新的ManagerState(由Manager的快照副本填充)。
  • 如果class Manager可以设为不可变:

      删除public IObservable<bool> IsEnabled { get; set; }

  • 定义实现ManagerSource的新类IObservable<Manager>
  • 每次以某种方式更新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 }

    请注意,此

    can

    像这样与对INotifyPropertyChanged的支持相结合(尽管我认为这是一个坏主意,因为支持以多种方式完成同一件事将最终使您的用户/消费者/同事感到困惑) -有点像System.Net.Sockets.Socket具有AcceptAcceptAsyncBeginAccept / 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 }
  • © www.soinside.com 2019 - 2024. All rights reserved.