Unity(C#)でAwaiterだけ使って間に合わせでCallback地獄をぶっ潰す


# tl; dr
ちゃんとUniTask勉強して使うのが安定だと思います
- https://github.com/Cysharp/UniTask

## 雑に解決する場合
これを使います
- https://github.com/furukazu/Awaiter/blob/master/Assets/Awaiter.cs

例
- https://github.com/furukazu/Awaiter/blob/master/Assets/AwaiterExample.cs

### 雑な説明
#### その1

これが

```csharp

public class SimpleCallbackComponent
{
    // 引数でコールバックを指定するようなよくある奴
    public void Open(Action onFinished){}

    // これを追加する
    public Awaiter OpenAwait()
    {
        var ret = new Awaiter();
        Open(() => { ret.SetResult(); });
        return ret;
    }
}

public class AwaiterExample 
{
    // 地獄の例
    public void TestCallbackComponent()
    {
        var simple = new SimpleCallbackComponent();
        simple.Open(() =>
        {
            Debug.Log("1");
            var simple2 = new SimpleCallbackComponent();
            simple2.Open(() =>
            {
                Debug.Log("2");
                var simple3 = new SimpleCallbackComponent();
                simple3.Open(() =>
                {
                    Debug.Log("3");
                });
            });
        });
    }    
}
```

こうなる

```csharp
    // 幸せな例
    public async void TestCallbackComponentAwait()
    {
        var simple = new SimpleCallbackComponent();
        await simple.OpenAwait();
        Debug.Log("1");
        
        var simple2 = new SimpleCallbackComponent();
        await simple2.OpenAwait();
        Debug.Log("2");
        
        var simple3 = new SimpleCallbackComponent();
        await simple3.OpenAwait();
        Debug.Log("3");
    }
```

### その2

これが

```csharp
public class CallbacksComponent
{
    // 引数でコールバックを複数指定してそのあげくに引数を伴って呼ばれたりするよくある奴
    // onOpened のあとに onClosed が呼ばれるものとする
    public void Open(Action onOpened,Action<int> onClosed){}

    // こんなのを追加する
    public Tuple<Awaiter, Awaiter<int>> OpenAwait()
    {
        var opened = new Awaiter();
        var closed = new Awaiter<int>();
        Open(
            () => { opened.SetResult(); }, 
            (result) => { closed.SetResult(result); });
        return Tuple.Create(opened, closed);
    }
}

// 地獄の例
public class AwaiterExample2 
{
    public void TestCallbacksComponent()
    {
        var simple = new CallbacksComponent();
        simple.Open(
            () => { Debug.Log("Opened 1"); },
            (result) =>
        {
            Debug.Log("Closed 1");
            
            var simple2 = new CallbacksComponent();
            simple2.Open(
                () => { },
                (result2) =>
                {
                    Debug.Log($"Closed 2: {result2}");
                    var simple3 = new CallbacksComponent();
                    simple3.Open(
                        () => { Debug.Log("Opened 3"); }, 
                        (result3) => { });
                });
        });
    }
```

こうなる

```csharp
    
    public async void TestCallbacksComponentAwait()
    {
        var simple = new CallbacksComponent();
        var (opened, closed) = simple.OpenAwait();
        await opened;
        Debug.Log("Opened 1");
        // var result = await closed;
        await closed;
        Debug.Log("Closed 1");
            
        var simple2 = new CallbacksComponent();
        //(opened, closed) = simple2.OpenAwait();
        (_, closed) = simple2.OpenAwait();
        // await opened;
        var result2 = await closed;
        Debug.Log($"Closed 2: {result2}");
        
        
        var simple3 = new CallbacksComponent();
        (opened,_) = simple3.OpenAwait();
        await opened;
        Debug.Log("Opened 3");
    }
}
```

Taskとかは知らん！ ちゃんとやりたければUniTask使え！！！