【UniRx】メッセージを変換するオペレータ #99
前回の成果
Observableを分岐させるオペレータについて学んだ。
今回やること
今回はメッセージの変換をするオペレータについてまとめます。
- 前回の成果
- 今回やること
- 値を変換したい
- 型変換をし、失敗時にはOnErrorを発行
- 型変換をし、失敗しても無視する
- 発行されたメッセージの値を別のObservableと合成
- ListのListの中身を発行
- メッセージにOn〇〇を付与
- 前回のメッセージ発行からの経過時間を表示
- メッセージにタイムスタンプを付与
- メッセージをUnit型に変換する
- 参考サイト様
値を変換したい
Select
メッセージで流れてきた値を別の値へと変換することができます。
値を変換する
/// <summary> /// 値を変換する /// </summary> private void ExcuteSelect() { Debug.Log("--------Change Type--------"); // 型変換 Observable .Range(0, 1) // intからstringに変換 .Select(x => x.ToString()) .Subscribe(x => { Debug.Log("Select onNext : " + x.GetType()); }, () => { Debug.Log("Select onCompleted"); }); Debug.Log("--------Change Value--------"); // 値を変換 Observable .Range(0, 1) // 値を変換 .Select(x => 1000) .Subscribe(x => { Debug.Log("Select onNext : " + x); }, () => { Debug.Log("Select onCompleted"); }); }
結果
intからstringの型変換や、0から1000の値の変換をしています。
型変換をし、失敗時にはOnErrorを発行
Cast
型を変更し、失敗時にはOnErrorを発行しそこでストリームを止めます。
似たオペレータにOfTypeが存在し、そちらはOnErrorを発行しません。
型を変換し、失敗時はonErrorを発行する
public class Enemy { public string Name { get; set; } }; public class Slime : Enemy { }; public class Drakee : Enemy { }; /// <summary> /// 型を変換し、失敗時はonErrorを発行する /// </summary> private void ExcuteCast() { Subject<Enemy> subject = new Subject<Enemy>(); subject .Cast<Enemy, Slime>() .Subscribe(x => { Debug.Log("Cast onNext : " + x.Name); }, error => { Debug.LogException(error); }, () => { Debug.Log("Cast onCompleted"); }); subject.OnNext(new Slime { Name = "スライム" }); // cast失敗 subject.OnNext(new Drakee { Name = "ドラキー" }); // 通らない subject.OnNext(new Slime { Name = "スライムベス" }); // 通らない subject.OnCompleted(); }
結果
スライムはSlime型に変換できるのでOnNextが発行されています。
ですが、ドラキーはDrakee型なので、Slime型に変換できずOnErrorが発行されます。
また、失敗した箇所以下のスライムベスとOnCompletedは通りません。
型変換をし、失敗しても無視する
OfType
型変換をし、失敗しても無視して次の処理へと移ります。
似たオペレータにCastが存在し、そちらは失敗時にOnErrorを発行します。
型変換をし、失敗しても無視する
public class Enemy { public string Name { get; set; } }; public class Slime : Enemy { }; public class Drakee : Enemy { }; /// <summary> /// 型変換をし、失敗しても無視する /// </summary> private void ExcuteOfType() { Subject<Enemy> subject = new Subject<Enemy>(); subject .OfType<Enemy, Slime>() .Subscribe(x => { Debug.Log("OfType onNext : " + x.Name); }, error => { Debug.LogException(error); }, () => { Debug.Log("OfType onCompleted"); }); subject.OnNext(new Slime { Name = "スライム" }); // cast失敗 subject.OnNext(new Drakee { Name = "ドラキー" }); // 通る subject.OnNext(new Slime { Name = "スライムベス" }); // 通る subject.OnCompleted(); }
結果
スライムはSlime型に変換できるのでOnNextが発行されています。
そして、次のスライムベスとOnCompletedが呼ばれます。
発行されたメッセージの値を別のObservableと合成
SelectMany
Observableと別のObservableを合成させて、新たな結果を発行することができます。
メッセージの値を元に別のObservableと合成する
/// <summary> /// メッセージの値を元に別のObservableと合成する /// </summary> private void ExcuteSelectManyObservable() { Subject<string> subject = new Subject<string>(); subject .SelectMany(x => Observable .Range(0, 3) .Select(y => x + y.ToString())) .Subscribe(x => { Debug.Log("SelectMany OnNext : " + x); } ,() => { Debug.Log("SelectMany OnCompleted"); }); subject.OnNext("A"); subject.OnNext("B"); subject.OnNext("C"); subject.OnCompleted(); }
結果
SelectManyで指定しているRangeの0~2の値と、OnNextでストリームに流れてくるA~Cの値が合成されています。
ListのListの中身を発行
SelectMany
List<List>のように、Listの中にListがあるものをforeachを使わずに発行することができます。
ListのListの中身
/// <summary> /// ListのListの中身 /// </summary> private void ExcuteSelectManyList() { List<string> list1 = new List<string> { "A", "B", "C" }; List<string> list2 = new List<string> { "D", "E", "F" }; List<string> list3 = new List<string> { "G", "H", "I" }; List<List<string>> listToList = new List<List<string>>(); listToList.Add(list1); listToList.Add(list2); listToList.Add(list3); listToList .ToObservable() .SelectMany(lists => lists) .Subscribe(x => { Debug.Log("List Value : " + x); }, () => { Debug.Log("OnCompleted"); }); }
結果
各要素が発行されています。
メッセージにOn〇〇を付与
Materialize
OnNext、OnError、OnCompletedをメッセージに付与することができます。
メッセージにonNext,onError,onCompletedの情報を付与
/// <summary> /// メッセージにonNext,onError,onCompletedの情報を付与 /// </summary> private void ExcuteMaterialize() { // onNextとonComplete IObservable<int> stream = Observable.Range(0, 3); Observable .Materialize(stream) .Subscribe(x => { Debug.Log("Materialize onNext : <color=blue>" + x + "</color>"); }, () => { Debug.Log("Materialize onComplete"); }); // onError Observable .Throw<Unit>(new Exception("Error Message")) .Materialize() .Subscribe(x => { Debug.Log("Materialize onNext : <color=blue>" + x + "</color>"); }); }
結果
メッセージにOn〇〇の情報が付与され、発行された値はかっこ内に入っています。
前回のメッセージ発行からの経過時間を表示
TimeInterval
前回のメッセージを発行した時間から、今回メッセージを発行した時間までの経過時間を表示することができます。
前回、値が流れてきたときからの経過時間を表示
/// <summary> /// 前回、値が流れてきたときからの経過時間を表示 /// </summary> private void ExcuteTimeInterval() { // キーが押されたらメッセージ発行 IObservable<Unit> input = this.UpdateAsObservable() .Where(_ => Input.anyKeyDown); // 前回、値が流れてきたときからの経過時間 Observable .TimeInterval(input) .Subscribe(x => { Debug.Log("TimeInterval : " + x.Interval); }); }
結果
前回キーが押された時間から、今回押された時間の経過時間を表示しています。
メッセージにタイムスタンプを付与
TimeStamp
メッセージにタイムスタンプを付与
/// <summary> /// メッセージにタイムスタンプを付与 /// </summary> private void ExcuteTimeStamp() { // キーが押されたらメッセージ発行 IObservable<Unit> input = this.UpdateAsObservable() .Where(_ => Input.anyKeyDown); // タイムスタンプを付与 Observable .Timestamp(input) .Subscribe(x => { Debug.Log("TimeStamp : " + x.Timestamp); }); }
結果
メッセージにタイムスタンプが付与されています。
メッセージをUnit型に変換する
AsUnitObservable
Unit型とは、UniRxで定義されているイベントのタイミングや通知したいものが何も無いときに使用するものになります。
以下のようにSelectを使用することで同じことが出来ます。
Select(_ => Unit.Default)
メッセージをUnit型に変換したい
/// <summary> /// メッセージをUnit型に変換したい /// </summary> private void ExcuteAsUnitObservable() { Observable .Range(0, 3) .AsUnitObservable() .Subscribe(x => { Debug.Log("AsUnitObservable onNext : " + x); }, () => { Debug.Log("AsUnitObservable onCompleted"); }); }
結果
Rangeで0~2の値を流そうとしていますが、Unit型になっています。
今回は以上となります。
ここまでご視聴ありがとうございました。