【UniRx】コルーチンをIObservable化する方法

# はじめに
コルーチンをIObservableにする方法を良く忘れてしまうので、備忘録もかねてメモ

# 環境
Windows 10

# コルーチンをIObservable化するメリット
コルーチンをIObservable化することで、非同期処理を**同期処理っぽく**書けるなどといったメリットがあります。

# とりあえずコルーチンを書いてみる
百聞は一見にしかず。適当なコルーチンを書いてみます。

以下はWikipediaから**卵かけご飯の情報を取得**するコルーチンです。 

```TestWWW.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestWWW : MonoBehaviour
{
    void Start()
    {
        this.StartCoroutine(this.GetTKG()); // コルーチンの実行
    }

    // Wikipediaから卵かけごはん(TKG)を取得するコルーチン
    private IEnumerator GetTKG()
    {
        WWW www = new WWW("https://ja.wikipedia.org/wiki/卵かけご飯"); // Wikipediaから卵かけごはんを取得
        yield return www;
        Debug.Log(www.text);
    }
}
```

## 実行結果
上記のTestWWW.csを適当なオブジェクトにアタッチしてゲームを実行すると以下のようなログが得られます。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/44288/f61a168c-018f-634c-55c6-68aa65821d5f.png)

Wikipediaから**卵かけごはん(TKG)が取得できます。**

# コルーチンをIObservable化する
ここからが本題ですが、このコルーチンを**IObservable化**してみようと思います。

```TestWWW.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;

public class TestWWW : MonoBehaviour
{
    void Start()
    {
        Observable.FromCoroutine<string>(observer => this.GetTKG(observer))
        .Subscribe(text =>
        {
            Debug.Log("Subscribe: " + text); // observer経由で流れてきた卵かけごはんをログ出力
        })
        .AddTo(this);

    }

    // Wikipediaから卵かけごはん(TKG)を取得するコルーチン
    private IEnumerator GetTKG(IObserver<string> observer)
    {
        WWW www = new WWW("https://ja.wikipedia.org/wiki/卵かけご飯"); // Wikipediaから卵かけごはんを取得する
        yield return www;
        Debug.Log(www.text);

        observer.OnNext(www.text); // Wikipediaから取ってきた卵かけごはんをobserver経由で外部に流す
        observer.OnCompleted(); // 完了
    }
}
```

## 実行結果
実行すると以下のようなログが出力されます。

![2.png](https://qiita-image-store.s3.amazonaws.com/0/44288/4703c3fc-5d11-d634-ce65-8e8f6f3298c3.png)


IObservableの**Subscribe時に**卵かけごはんが**ログ出力**されていることが確認できました。


# コルーチンをIObservable化する手順
詳細に解説すると、以下のような手順でコルーチンをIObservable化することができます。

手順1: コルーチンの外部に流したいデータの**変数型Tを決める**
手順2: コルーチンの引数に**IObserver\<T>**な変数を追加
手順3: **Observable.FromCoroutine\<T>()**を実行

## 1.変数型Tを決める
今回は**string**型であるWWW.textを外部に流したいので、変数型**Tはstring**になります。

## 2.引数にIObserver\<T>な変数を追加

```csharp:変更前のコルーチン
private IEnumerator GetTKG()
```

```csharp:変更後のコルーチン
private IEnumerator GetTKG(IObserver<string> observer)
```

引数に追加したobserverを経由してデータの受け渡しを行います。

## 3.Observable.FromCoroutine\<T>()を実行
```
Observable.FromCoroutine<string>(observer => this.Get(observer))
```

Observable.FromCoroutine<T>の返却値はIObservable<T>になっているので、
コルーチンの**IObsevable化は完了**です。

# 活用例
コルーチンをIObservable化したものをそのまま外部に流す、といったこともできます。
ロジックの**分離**ができてたいへん便利です。


## IObservableの提供側

```TestWWW.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;

public class TestWWW : MonoBehaviour
{
    // Wikipediaから卵かけごはんを取得するIObservable
    public IObservable<string> GetTKGAsObservable()
    {
        return Observable.FromCoroutine<string>(observer => this.GetTKG(observer));
    }

    // Wikipediaから卵かけごはんを取得するコルーチン
    private IEnumerator GetTKG(IObserver<string> observer)
    {
        WWW www = new WWW("https://ja.wikipedia.org/wiki/卵かけご飯"); // Wikipediaから情報を取得
        yield return www;

        observer.OnNext(www.text); // 取得してきたデータをobserver経由で外部に流す
        observer.OnCompleted(); // 完了
    }
}
```

## IObservableの利用側

```NewBehaviourScript.cs
using UnityEngine;
using UniRx;

public class NewBehaviourScript : MonoBehaviour
{
    [SerializeField] private TestWWW testWWW;

    void Start()
    {
        testWWW.GetTKGAsObservable()
        .Subscribe(text =>
        {
            Debug.LogFormat("Wikipediaから卵かけごはんをとってきたよ\n{0}", text);
        });
    }
}
```

## 実行結果

実行すると以下のような結果が得られます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/44288/93d1ff7b-6758-a1a1-2a94-dba222418285.png)

**卵かけごはんが取得できました(完)**

# 参考URL
UniRx入門 その5 -コルーチンとの併用-
https://qiita.com/toRisouP/items/c4b9c5701dd6c991b481