RX弱者がRXの基本の「き」を整理してみる

この記事は C# Advent Calendar 2018 21日目の記事です。

#はじめに

いつもコードを書いていて、
何か詰まるところがあると思っていたんですが
最近それがRXというもので、
自分がかなりのRX弱者ということに気づいたので
これを機に整理していこうと思います。

C#のアドベントカレンダーなので
C#のRXについて書こうと思ったのですが
普段さわっているものがUnityC#なので
具体的なものについては、
純粋なC#のRXではなくUniRXを書いています。

情報で間違っている部分があれば、
修正していただくか、教えていただけると助かります。

#RXとは？
・Reactive Extensionsの略
・GoFのデザインパターンの1つであるObserverパターンを実装するフレームワーク
・非同期 / イベント / 時間に関する処理をLINQで書ける

#Observerパターンとは？
Observer：観察
Subject(観察対象)の状態が変化すると、
Observer(観察者)に対して通知される。
状態変化に応じた処理を記述するときに使用される。
(ボタンを押したら○○する、攻撃を受けたらHPを減らす、など)

RXでは、
Subject=IObservable<T>
Observer=IObserver<T>

Observerパターンという名前だが、
実際にはSubject(IObserver<T>)は
受動的に通知を待つだけなので
Publish-Subscribe(発行-購読)パターンとも呼ばれる。

#RXにおいて重要なもの
・ストリーム
・メッセージ
・購読
・オペレータ

###ストリーム
ストリーム：川、小川
![bb.png](https://qiita-image-store.s3.amazonaws.com/0/299216/b09e33b6-eb5c-7497-d8a3-d1e40ebcb365.png)
プロバイダ、データソースとも呼ばれる。
イメージとしては、
ストリームという川がイベントを運び状態の通知を行う感じ。
時間軸があることがポイント。

###メッセージ
![bc.png](https://qiita-image-store.s3.amazonaws.com/0/299216/2a837d1f-f579-8801-cc6f-4668ee041b32.png)
ストリームから流れてくる値、
IObservable<T>が発行して、IObserbabler<T>に伝える。

###購読
![adpng.png](https://qiita-image-store.s3.amazonaws.com/0/299216/5b2243d0-3d89-1bdd-1d1b-6b45ea25d888.png)
IObserbable<T>がIObservable<T>が発行した
メッセージを受け取って処理を行う。(Subscribe)
種類は以下の3つ

void OnNext(T value)→通常の処理を行う
void OnError(Exception ex)→発生した例外を受け取って処理を行う
void OnCompleted()→通知が終了したときの処理を行う

onComplete と onError のどちらかが発生した時点でストリームは終了する

###オペレータ
オペレータ：操作者
![bf.png](https://qiita-image-store.s3.amazonaws.com/0/299216/644cec6b-528b-90a7-8176-d3e99c1dd454.png)
ストリームを加工したり(Whereとか)、作成したりする
メソッドチェーンで繋げて書くことができる

#基本のかたち
流れてきたメッセージをオペレータで濾過してSubscribeで処理

```csharp
Observable./*オペレータ*/.Subscribe(//したい処理);
```
メッセージはたくさん流れてくるので、
オペレータで
残すものを選んだり（Where）
使いやすいように加工したりできます（Select）

##オペレータ

###Linqのかたちで使える
Where

```csharp
//偶数のときだけ処理をする
Observable.Range(0,10)
        .Where(x=>x%2==0)
        .Subscribe({
            Console.WriteLine("偶数です");
        });
```

Select

```csharp
//10倍にする（処理の中で変化させた値を使用できる）
Observable.Range(0,10)
        .Select(x=>x*10)
        .Subscribe({
            Console.WriteLine(x);
        });
```

Range()は引数で渡された数字を流すストリームを作ります。

##オペレータ以外
###Subject
C#RxではSubjectは異質な存在らしいですが、
UniRxでは基本の「き」らしいです。

特徴
・IObservable<T>インターフェースとIObserver<T>インターフェースを両方実装したクラス
Subject自体をsourceとして、
任意のタイミングでOnNext()OnError()OnCompleted()を呼び出せる
＝勝手にメッセージが流れてくるのではなく、
わざと外で変化させて値を流し込むもの

```csharp
//入力

//登録
var s = new Subject<nt>();
s.Subscribe(
    x => Console.WriteLine("OnNext");
    ex => Console.WriteLine("OnError");
    () => Console.WriteLine("OnCompleted")
);

//発火
s.OnNext();
s.Completed();

//出力
OnNext
OnCompleted
```
https://qiita.com/acple@github/items/8d3a4d3414fa59adff70
https://qiita.com/ralph/items/f7205c8171826cc2153b
https://qiita.com/toRisouP/items/2f1643e344c741dd94f8

###時間/イベント/非同期
イベントと非同期については、
よく分からなかったので
ほぼ参考のみ載せました。

####時間
Observable.Timer()
発火タイミングを設定できる

```csharp
//5秒後に１秒間隔で値が発行される
var t = Observable.Timer(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1));
var s = t.Subscribe(
    x => Console.WriteLine("OnNext"),
    ex => Console.WriteLine("OnError"),
    () => Console.WriteLine("OnCompleted")
);
```
5秒後に一秒間隔で
「OnNext」が表示され続け、
エラーがあった場合に「OnError」
s.Dispose()で「OnCompleted」

https://blog.xin9le.net/entry/2012/01/07/211152
https://blog.okazuki.jp/entry/20111106/1320584830
https://qiita.com/Marimoiro/items/a72b60315c797c19a27c

####イベント
難しかったので、調べたことと参考のみ。

FromEvent()でeventをObservableに変換する。

https://sakapon.wordpress.com/2016/10/28/reactive-drag/
http://any-programming.hatenablog.com/entry/2017/05/11/155410
https://befool.co.jp/blog/8823-scholar/unirx-from-event-args/
https://ufcpp.net/study/csharp/sp_event.html
https://qiita.com/Temarin/items/be5f9cea260580327700

###非同期
こちらも、難しかったので、調べたことと参考のみ。

Start,toAsync
発火させてから非同期で処理を開始できる。

https://blog.okazuki.jp/entry/20100928/1285645729
https://blog.xin9le.net/entry/2012/01/15/163827
http://light11.hatenadiary.com/entry/2018/11/07/225617

###疑問点
Repeat()は、ストリームを再生成するものらしいのですが
そうなるとRepeatがかかるたびに、
ストリームが増えていって
無駄なものが奥で走ることになるんじゃなかろうかと
思うのですが、いまだに分かっていません。
https://qiita.com/toRisouP/items/59d10ddec2e89b86600c

#他に覚えておきたいもの
###unit構造体
(rxに限らないので、あんまり関係なかった)
返り値が本当は必要ではないけど、
何らかの返り値を渡さなくてはいけないときに使うもの
voidの役割をしてくれる
通知のみしたいときなどに使う

```csharp
var s=new Subject<Unit>();
s.Observable(Console.WriteLine);

s.OnNext("通知");
```
https://qiita.com/tamy0612/items/bfc4b034d94b7fee1b82
https://ufcpp.net/study/csharp/st_function.html
https://qiita.com/alucky0707/items/a677e5c9850aa765dd55
https://qiita.com/Temarin/items/107fa2e39f427e591dbd
https://qiita.com/toRisouP/items/851087b4c990d87641e6

#さいごに
基本の「き」をまとまってないですが、まとめてみました。
何となく概要がつかめたら後は書くだけ、
だと思っているので
あやふやな部分や空白は
書いてなじませていこうと思います。
読んでいただき、ありがとうございました。

#参考
https://qiita.com/acple@github/items/6cfee916f09632037a6e
http://introtorx.com/Content/v1.0.10621.0/02_KeyTypes.html#KeyTypes
https://blog.xin9le.net/entry/rx-intro
https://www.slideshare.net/okazuki0130/reactive-extensionsv01
https://techinfoofmicrosofttech.osscons.jp/index.php?Reactive%20Extensions%EF%BC%88Rx%EF%BC%89
https://speakerdeck.com/adarapata/bu-kunaireactive-extensions?slide=22
https://blog.okazuki.jp/entry/2015/03/23/203825
http://rxwiki.wikidot.com/marble-diagrams
http://wilfrem.github.io/learn_rx/operators.html
http://kmycode.hatenablog.jp/entry/2017/09/30/181312
https://qiita.com/hiruberuto/items/39e4126f470d8b84b291
https://tech.recruit-mp.co.jp/front-end/rxjs-intro/
https://liginc.co.jp/web/js/151272
https://qiita.com/Temarin/items/be5f9cea260580327700
https://qiita.com/Temarin/items/c2066394e91966c2d4ef
http://okapies.hateblo.jp/entry/2015/03/04/031148
http://tassi-yuzukko.hatenablog.com/entry/2018/06/04/150921
http://tc-kazuki.hatenablog.jp/entry/2017/12/16/160204
http://garicchi.hatenablog.jp/entry/2014/09/17/200000
http://noriok.hatenadiary.jp/entry/2018/08/25/191945
https://www.slideshare.net/torisoup/uni-rx
https://qiita.com/toRisouP/items/3cf1c9be3c37e7609a2f