Должен ли я использовать dispatcher.Invoke (…) или ObserveOn (диспетчер)?

1

Мне был предоставлен некоторый код для работы над тем, куда диспетчер передается модели представления в свой конструктор. Теперь мне интересно, следует ли мне использовать 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 - лучший вариант.

Это хороший или плохой ход? В тот момент я использую оба метода равномерно. Я намерен перейти к одному из них, но сначала хочу знать правильный путь.

  • 1
    Я бы сказал, что это сложный вопрос, если у вас есть расширения Reactive и вам не нужно нигде Invoke() , почему бы не использовать расширения? Вот почему это там. Перефакторите это позже, если это станет уместным / имеет смысл.
Теги:
reactiveui
system.reactive

2 ответа

4
Лучший ответ

Я бы посмотрел, может ли я получить экземпляр 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());
  • 0
    Добавление еще одного замечания ... использование планировщика внутри пользовательского метода полностью нарушает SRP, а также может усложнить тестирование. Метод должен быть разработан, чтобы делать что-то, а не знать, где это должно быть сделано. Для этого и существует наблюдаемая композиция и оркестровка.
  • 0
    Кроме того, если в коде есть несколько мест, которые вызывают этот метод, просто перенаправьте этот код, чтобы он использовал исходное планирование. Вот почему у нас есть такие операторы, как Merge . Это дает нам более точный контроль.
Показать ещё 3 комментария
3

Функционально нет никакой разницы. Однако я бы использовал ObserveOn(dispatcher) и оставил SomeMethod() как есть. Вы также можете позже вызвать SomeMethod() из потока пользовательского интерфейса, и в этом случае диспетчеризация будет ненужной. Я бы сказал, что ответственный за вызов код должен знать, работает ли он в потоке пользовательского интерфейса или нет, и поэтому требуется ли диспетчеризация.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню