具有两个属性,其中一个类型为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);
}
}
您发布的代码不是如何使用反应式编程范例的好例子。
ObservableCollection
,但在ObservableCollection
上下文中对(可观察到的)术语的(误用)完全与无功编程中的Observable
。进行响应式编程时,一个Observable是数据对象流的源(或发射器)(请注意,流[[can为空(从不发出任何东西))或仅在其之前发出一个对象关闭自己,或每秒发出数千个对象)。
IObservable
视为“ IEnumerable<T>
-推”(与具有[pull]语义的普通IEnumerable<T>
相比。]]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
具有Accept
,AcceptAsync
,BeginAccept
/ 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
}