Мне был предоставлен некоторый код для работы над тем, куда диспетчер передается модели представления в свой конструктор. Теперь мне интересно, следует ли мне использовать ObserveOn(dispatcher)
или dispatcher.Invoke(...)
когда я хочу, чтобы что-то выполнялось в потоке пользовательского интерфейса.
Например, я мог бы это сделать:
this.WhenAny(me => me.SomeValue, _ => Unit.Default)
.ObserveOn(dispatcher)
.Subscribe(_ => SomeMethod());
...
private void SomeMethod()
{
//do some stuff
}
или я мог бы это сделать:
this.WhenAny(me => me.SomeValue, _ => Unit.Default)
.Subscribe(_ => SomeMethod());
Что тогда означало бы, что я мог бы сделать это вместо этого:
private void SomeMethod()
{
dispatcher.Invoke(new Action(() =>{//do some stuff});
}
Есть ли разница между ними?
Меня беспокоит, что, если я хочу вызвать SomeMethod() в какой-то другой части кода, который не срабатывает при изменении SomeValue? Затем мне нужно было бы dispatcher.invoke(new Action(() => someMethod()));
, что заставляет меня думать, используя dispatcher.Invoke(...)
Invoke dispatcher.Invoke(...)
внутри SomeMethod - лучший вариант.
Это хороший или плохой ход? В тот момент я использую оба метода равномерно. Я намерен перейти к одному из них, но сначала хочу знать правильный путь.
Я бы посмотрел, может ли я получить экземпляр IScheduler
который является реализацией DispatcherScheduler
. Таким образом, я смог бы протестировать свой код с помощью TestScheduler
без необходимости попадать в недра диспетчеров и нажав рамки и т.д. После того, как у вас есть экземпляр IScheduler
вы можете просто использовать его для ObserveOn(dispatcherScheduler)
.
Я также согласен с @mclaassen, что вы должны знать, какой планировщик/поток вы используете, и, следовательно, нужно ли вам планировать/вызывать или нет. Например, если вы наблюдаете события INotifyPropertyChanged
то вы будете на диспетчере, поэтому вам не нужно отправлять. Если вы получаете ответ от сетевого вызова или тяжелого расчета, вы, вероятно, находитесь в другом потоке, поэтому вам нужно запланировать/отправить, чтобы вернуться к диспетчеру. Цена
Стандартный шаблон в Rx для этого - либо не планировать, потому что вы уже на правильной нити:
//this is a ViewModel, and property changes occur on the dispatcher
this.WhenAny(
vm => vm.PropertyA,
vm => vm.PropertyB,
_ => Unit.Default)
.Subscribe(_ => SomeMethod());
Кроме того, примените шаблон SubscribeOn
/ObserveOn
, чтобы выйти из текущего потока, выполнить работу и затем получить результаты в исходном потоке.
myRepo.GetDataFromNetwork()
.SubscribeOn(taskPoolScheduler)
.ObserveOn(dispatcherScheduler)
.Subscribe(_ => SomeMethod());
Merge
. Это дает нам более точный контроль.
Функционально нет никакой разницы. Однако я бы использовал ObserveOn(dispatcher)
и оставил SomeMethod()
как есть. Вы также можете позже вызвать SomeMethod()
из потока пользовательского интерфейса, и в этом случае диспетчеризация будет ненужной. Я бы сказал, что ответственный за вызов код должен знать, работает ли он в потоке пользовательского интерфейса или нет, и поэтому требуется ли диспетчеризация.
Invoke()
, почему бы не использовать расширения? Вот почему это там. Перефакторите это позже, если это станет уместным / имеет смысл.