C#でコールバックをTaskにしてawaitしたい

C#でコールバックの値を同期的に取得したい時がある。

Rxを使ってJavascriptのPromise的なことをする。

// コールバックで値を返すメソッド
private void Foo(Action<string> arg)
{
    arg("qawsedrf");
}
// コールバックの値を取得してTaskにして返すメソッド
private Task<string> Bar()
{
    return Observable.Create<string>(observer =>
    {
        Foo(a =>
        {
            observer.OnNext(a);
            observer.OnCompleted();
        });
        
        return null;
    }).ToTask();
}
string value = await Bar();
    
Console.WriteLine(value);  // qawsedrf

Observable.Createでコールバックからの値を流すObservableを作り、 ToTaskでTaskに変換できる。


これを活用して以下のようなことができる。

string dataPath = await Observable.Create<string>(observer =>
{
    return Observable.Return(Unit.Default).ObserveOnMainThread().Subscribe(_ =>
    {
        observer.OnNext(Application.persistentDataPath);
        observer.OnCompleted();
    });
}).ToTask();

Unityの場合、メインスレッド上でなければUnityAPIを呼び出すことができないが、 こうすることでUnityAPIである Application.persistentDataPath の呼び出しだけメインスレッドで行う。


こんなメソッドを作ればスレッドに囚われないGetComponentができる。

private Task<T> GetComponent2<T>(GameObject gameObject)
{
    return Observable.Create<T>(observer =>
    {
        return Observable.Return(Unit.Default).ObserveOnMainThread().Subscribe(_ =>
        {
            T component = gameObject.GetComponent<T>();
            observer.OnNext(component);
            observer.OnCompleted();
        });
    }).ToTask();
}
Rigidbody rb = GetComponent2<Rigidbody>(this.gameObject)

コメント

このブログの人気の投稿

fontconfigの設定

VLCでBlu-rayを再生

UEFIのブートオーダーを一時的に変更する