LoginSignup
17
9

More than 3 years have passed since last update.

UniRxとUniTask 相互変換の変わったパターン紹介

Last updated at Posted at 2019-12-23

はじめに

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>

ObservableUniTaskを扱う場合に、それを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>>

ObservableUniTaskを扱う場合に、それを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[]>

まとめ

UniRxUniTaskはだいたいどんなパターンでもそれぞれに変換することができます。
両者を組み合わせて使い、必要に応じて変換をかけるとよいでしょう。

17
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
9