我在这个网站上读到comment关于如何使用IObservable的说法..
作为一般规则(指南),我强烈建议不要将IObservable<T>
作为方法的参数。显而易见的警告是,如果该方法是新的Rx运算符,例如Select
,MySpecialBuffer
,Debounce
等。
因此,我一直在尝试将此建议应用于我的代码,并继续遇到违反此规则似乎很方便的情况。请查看下面的代码并比较PersonSelectorViewModelA
和PersonSelectorViewModelB
。这些视图模型可能绑定到ComboBox的ItemsSource和SelectedValue属性。
我喜欢PersonSelectorViewModelA
- 它在构造函数中使用IObservable - 更好,因为一旦构造它,它会自动响应添加到地址簿的人和从地址簿添加的人。它没有任何保姆照顾其业务和责任。 PersonSelectorViewModelB
需要更多“维护和关注”,因为实例化它的代码需要记住定期调用UpdatePeople
。
那么哪种方法更好?
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Guid Id { get; set; }
}
public interface IAddressBookRepository
{
void AddOrUpdatePerson(Person p);
void DeletePerson(Guid id);
IObservable<IEnumerable<Person>> People();
}
public class PersonSelectorViewModelA : BindableBase
{
Guid? _selectedPersonId = null;
ObservableCollection<Person> _peopleCollection = new ObservableCollection<Person>();
IObservable<IEnumerable<Person>> _peopleSource;
IDisposable _subscription;
public PersonSelectorViewModelA(IObservable<IEnumerable<Person>> people)
{
_peopleSource = people;
}
public void OnNavigateTo()
{
_subscription =
_peopleSource
.Select(i => i.ToArray())
.Subscribe(i =>
{
_peopleCollection.Clear();
foreach (var p in i)
{
_peopleCollection.Add(p);
}
if (!i.Any(j => j.Id == SelectedPersonId))
{
SelectedPersonId = null;
}
});
}
public void OnNavigateAway() => _subscription?.Dispose();
public Guid? SelectedPersonId {
get { return _selectedPersonId; }
set { SetProperty(ref _selectedPersonId, value); }
}
public ObservableCollection<Person> People => _peopleCollection;
}
public class PersonSelectorViewModelB : BindableBase
{
Guid? _selectedPersonId = null;
ObservableCollection<Person> _peopleCollection = new ObservableCollection<Person>();
public void UpdatePeople(IEnumerable<Person> people)
{
_peopleCollection.Clear();
foreach (var p in people)
{
_peopleCollection.Add(p);
}
if (!people.Any(j => j.Id == SelectedPersonId))
{
SelectedPersonId = null;
}
}
public Guid? SelectedPersonId {
get { return _selectedPersonId; }
set { SetProperty(ref _selectedPersonId, value); }
}
public ObservableCollection<Person> People => _peopleCollection;
}
答案 0 :(得分:1)
对于反应式ICommand,命令主机通常会知道何时启用和禁用该命令,并且可以手动(外部)而不是构造IObservable,然后将其传递给命令的构造函数。同样适用于显示FirstName和LastName串联的反应式FullName属性;使FullName成为IObserver更简单,而不是构建IObservable并将其传递给FullName属性的构造函数。因此,对于这些例子,我明白你的观点。
我的数据层包含IObservable<Person[]> GetPeople(string city)
和IObservable<Person> GetPerson(Guid id)
等功能,因此视图可以显示最新信息。这一层并不知道它的消费者是谁;有许多需要此数据的视图模型。假设一个消费者是一个人物选择者&#34;视图模型由另一个视图模型X托管。而不是让X订阅可观察对象并从外部驱动&#34;人员选择器&#34;它所拥有的,我给了人们选择&#34;在它的构造函数中的observable,所以X可以更加放手。 X并不关心人们选择器如何完成它的工作 - 它只是希望它能够做到这一点。 X&#34;了解&#34;可观察的,但只需要从一些数据层中获取它并使用它来构建人员选择器。
我认为这类似于WPF ListView。您可以将ListView的ItemsSource属性设置为支持INotifyCollectionChanged的集合,然后ListView订阅事件并自动更新其内容。这个数据绑定比拥有ListView订阅列表更改的视图模型更简单,并在ListView上调用一些UpdateItems方法。
听起来你几乎从不将一个observable传递给一个对象的构造函数。因此,在构造函数依赖注入方面,一个类不应该依赖于可观察的序列。但这可能是正确的,可能不是你所说的。也许我没有在原始问题中正确解释这个场景。否则,一个类只能依赖于它创建的可观察对象(奇怪的)或它通过对其依赖项的方法调用所捕获的可观察对象(类似于构造函数注入)。
答案 1 :(得分:0)
我的标准建议仍然有效。 你的代码有效,所以这是我的看法。 我相信让计算机做你想做的事情并不是很难,但让另一个人明白你想让计算机去做的事情要困难得多。
我认为您要么选择B(从外部更新的虚拟VM),要么传入IAddressBookRepository
。
但是传入IObservable<T>
IMO只是很奇怪。
如果我们认为IObservable<T>
只是Rx实现的回调/观察者模式。
接下来我们知道观察者模式是为了我们想要一个我们依赖的系统,给我们回电话,而不是明确地了解我们。
但是,如果我们传入IObservable<T>
,那么传递它的东西清楚地知道IObservable<T>
然后它正在创建的东西。
那么在这里购买我们的回调机制是什么期望双向间接?