はじめに
UniRxのObservable
と、UniTask
はそれぞれ相互変換することができます。
今回はその中でも少し変わった変換パターンを紹介したいと思います。
※ System.Linq
UniRx
UniRx.Async
のusingを忘れずに
IEnumerable<UniTask<T>>
-> IObservable<T>
複数のUniTask<T>
をまとめて、1つのIObservable<T>
にする方法です。
やり方が何パターンかあります。
// 対象
IEnumerable<UniTask<string>> tasks = CreateSample();
// ---
// 並列にまとめる(要素の順序を無視して、終わったものから結果を返す)
IObservable<string> parallel = tasks
.Select(x => x.ToObservable()) // IE<IO<T>>
.Merge(); // IO<T>
// 直列にまとめる(要素の先頭から順番に結果を返す)
IObservable<string> sequential = tasks
.Select(x => x.ToObservable()) // IE<IO<T>>
.Concat(); // IO<T>
// 全部終わってからまとめて結果をとるなら(IO<IE<T>>)
IObservable<IList<string>> whenAll = tasks
.Select(x => x.ToObservable()) // IE<IO<T>>
.Zip(); // IO<IList<T>>
// でも、全部まとめてとるならUniTask.WhenAllでいいのでは?
UniTask<string[]> whenAll2 = UniTask.WhenAll(tasks);
UniTask<IEnumerable<T>>
-> IObservable<T>
さっきとネストの仕方が逆のパターン。
UniTask<IE<T>>
を分解して1つのIObservable<T>
にする方法です。
2パターンあるけど結果は同じです。
// 対象
UniTask<IEnumerable<string>> task = CreateSample();
// パターン1
IObservable<string> p1 = task
.ToObservable() // IO<IE<T>>
.Select(x => x.ToObservable()) // IO<IO<T>>
.Merge(); // IO<T>
// パターン2
IObservable<string> p2 = task
.ToObservable() // IO<IE<T>>
.SelectMany(x => x.ToObservable()); // IO<T>
IObservable<T>
-> UniTask<IEnumerable<T>>
IObservable<T>
が発行するすべてのメッセージを「まとめて」待ち受けるUniTask<T>
を作りたい場合。
// 対象
IObservable<string> observable = CreateSample();
// ToArray()してからToUniTask()でOK
UniTask<string[]> task = observable.ToArray().ToUniTask();
IObservable<UniTask<T>>
-> IObservable<T>
Observable
がUniTask
を扱う場合に、それを1つのObservable
にまとめる。
// 対象
IObservable<UniTask<string>> observable = CreateSample();
// 並列(終わった順に結果を出すなら)
IObservable<string> parallel = observable.SelectMany(x => x.ToObservable());
// 直列(もとのIO<T>から発行された順序を維持するなら)
IObservable<string> sequential = observable.Select(x => x.ToObservable()).Concat();
IObservable<UniTask<T>>
-> UniTask<IEnumerable<T>>
Observable
がUniTask
を扱う場合に、それをUniTask
側にまとめる。
IObservable<UniTask<string>> observable = CreateSample();
// 結果は先に終わったUniTaskの順番になる
UniTask<string[]> task = observable
.SelectMany(x => x.ToObservable()) // IO<IO<T>>
.Merge() // IO<T>
.ToArray() // IO<T[]>
.ToUniTask(); // UniTask<T[]>
UniTask<IObservable<T>>
-> IObservable<T>
UniTask
の中にObservable
が入り込んじゃった場合。
// 対象
UniTask<IObservable<string>> task = CreateSample();
// taskをIO<IO<T>>に変換してからMerge()
IObservable<string> observable = task.ToObservable().Merge();
UniTask<IObservable<T>>
-> UniTask<IEnumerable<T>>
UniTask
の中にObservable
が入り込んじゃったものを、今度はUniTask
側にまとめる場合。
// async/await使っちゃうのが楽
private async UniTask<IEnumerable<string>> Unwrap(UniTask<IObservable<string>> task)
{
var observable = await task;
return await observable.ToArray();
}
IObservable<IObservable<T>>
-> UniTask<IEnumerable<T>>
こんなシチュエーションあるのかよくわからないけど。
IObservable<IObservable<string>> observable = CreateSample();
UniTask<string[]> task = observable
.SelectMany(x => x) // IO<T>
.ToArray() // IO<T[]>
.ToUniTask(); // UniTask<T[]>
まとめ
UniRx
とUniTask
はだいたいどんなパターンでもそれぞれに変換することができます。
両者を組み合わせて使い、必要に応じて変換をかけるとよいでしょう。