Rx の SelectMany について勘違いしていた
Rxは便利すぎるのですが、まだ不慣れな私です。
ReactivePropertyを用いてMVVMパターンを組み立てていたところ、以下のようなシーンに遭遇しました。
以下、単純化したサンプルです。
example.cs
using System;
using System.Linq;
using System.Reactive.Linq;
using System.Threading;
using Prism.Mvvm;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
namespace ConsoleExample
{
class Model1 : BindableBase
{
private int _number = 0;
public int Number
{
get { return _number; }
set { SetProperty(ref _number, value); }
}
}
class Model2 : BindableBase
{
private Model1 _model1 = null;
public Model1 Model1
{
get { return _model1; }
set { SetProperty(ref _model1, value); }
}
}
class ViewModel
{
public Model2 Model2 { get; }
public ReactiveProperty<int> Number { get; }
public ViewModel()
{
Model2 = new Model2();
Number = Model2
.ToReactivePropertyAsSynchronized(m2 => m2.Model1)
.Where(m1 => m1 != null)
// ここのSelectMany
.SelectMany(m1 => m1.ToReactivePropertyAsSynchronized(x => x.Number))
.ToReactiveProperty(0);
}
}
class View
{
private ViewModel _viewModel;
public View(ViewModel viewModel)
{
_viewModel = viewModel;
_viewModel.Number.Subscribe(x => Console.WriteLine(x));
}
}
class Program
{
static void Main(string[] args)
{
var viewModel = new ViewModel();
var view = new View(viewModel);
var model1_1 = new Model1();
var model1_2 = new Model1();
Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1)).Subscribe(x => model1_1.Number = (int)x);
Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1)).Subscribe(x => model1_2.Number = (int)(x * 10));
viewModel.Model2.Model1 = model1_1; // 1, 2, 3...
Thread.Sleep(5500); // 5.5秒待つ
viewModel.Model2.Model1 = model1_2; // 10, 20, 30...
Console.ReadLine();
}
}
}
出力は以下のようになります。
0
1
2
3
4
5
50
60
6
70
7
80
8
90
9
100
10
このように、model1_1とmodel1_2の内容が混ざり合っています。
私は当初、以下のようにmodel1_1からmodel1_2へ切り替わると思っていました。
0
1
2
3
4
5
50
60
70
80
90
100
しかし、そうはなっていません。
SelectManyは、以下の処理と同じだったのです。
example.cs
Select(m1 => m1.ToReactivePropertyAsSynchronized(x => x.Number)).Merge()
// ↑SelectMany(m1 => m1.ToReactivePropertyAsSynchronized(x => x.Number))と同じ結果
model1_1とmodel1_2が混ざり合わずに切り替わるようにするためには、以下のようにします。
example.cs
Select(m1 => m1.ToReactivePropertyAsSynchronized(x => x.Number)).Switch()
Author And Source
この問題について(Rx の SelectMany について勘違いしていた), 我々は、より多くの情報をここで見つけました https://qiita.com/hiki_neet_p/items/4a8873920b566568d63b著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .