# Awaitable のコード例リファレンス

> Solve common asynchronous programming problems with a reference of Awaitable code examples.

このリファレンスの例は、非同期コードの記述時に経験する一般的なシナリオに対する、`Awaitable` での解決策を示しています。

## 非同期テスト##asynchronous-tests

Unity の [Test Framework](/engine/6000.0/manual/scripting/environment-and-tools/testing-editortestsrunner.md) は、`Awaitable` を有効なテストの戻り値の型として認識しません。しかし、以下の例は、`IEnumerator` の `Awaitable` 実装を使用して非同期テストを記述する方法を示しています。

```lang-csharp
[UnityTest]
public IEnumerator SomeAsyncTest(){
    async Awaitable TestImplementation(){
        // test something with async / await support here
    };
    return TestImplementation();
}
```

## フレームコルーチン##frame-coroutines

`Awaitable` クラスのフレーム関連の非同期メソッドを使用して、イテレーターベースのコルーチンの代わりに、非同期の Unity コルーチンを作成できます。

```lang-csharp
async Awaitable SampleSchedulingJobsForNextFrame()
{
    // Wait until end of frame to avoid competing over resources with other Unity subsystems
    await Awaitable.EndOfFrameAsync(); 
    var jobHandle = ScheduleSomethingWithJobSystem();
    // Let the job execute while the next frame starts
    await Awaitable.NextFrameAsync();
    jobHandle.Complete();
    // Use results of computation
}

JobHandle ScheduleSomethingWithJobSystem()
{
    ...
}
```

### 条件付き待機##conditional-wait

イテレーターベースのコルーチンでは、デリゲートが `true` を評価するまで、[WaitUntil](/engine/6000.0/script-reference/unity-engine/wait-until.md) はコルーチンの実行をサスペンドします。キャンセルトークンを使用して条件が変更されるまでメソッドを待機させることで、`Awaitable` を返す非同期メソッドと同等の動作を作成できます。

```lang-csharp
public static async AwaitableUntil(Func<bool> condition, CancellationTokenSource cancellationToken)
{
   while(!condition()){
     cancellationToken.ThrowIfCancellationRequested();
     await Awaitable.NextFrameAsync();
  }
}
```

その後、以下のようにキャンセルトークンを渡すことができます。

```lang-csharp
cancellationTokenSource = new CancellationTokenSource();
currentTask = AwaitableUntil(myCondition, cancellationTokenSource.Token);
```

## リソースの非同期ロード##loading-resources-asynchronously

非同期のリソースロード操作を `await` して、メインスレッドをブロックしないようにすることができます。

```lang-csharp
public async Awaitable Start()
{
    // Load texture resource asynchronously
    var operation = Resources.LoadAsync("my-texture");
    // Return control to the main thread while the resource loads
    await operation;
    var texture = operation.asset as Texture2D;
}
```

## 合成##composition

同じメソッド内で複数の異なる `await` に互換性のある型を `await` できます。

```lang-csharp
public async Awaitable Start()
{
    await CallSomeThirdPartyAPIReturningDotnetTask();
    await Awaitable.NextFrameAsync();
    await SceneManager.LoadSceneAsync("my-scene");
    await SomeUserCodeReturningAwaitable();
    ...
}
```

## .NET タスクでの Awaitable のラッピング##wrapping-awaitable-in-.net-task

`Awaitable` の制限のいくつかを回避するために、.NET `Task` でラップします。これには割り当ての手間がかかりますが、`Task` API から `WhenAll` や `WhenAny` などのメソッドにアクセスできます。これを行うには、独自のカスタム `AsTask` 拡張メソッドを次のように記述します。

```lang-csharp
// Implement custom AsTask extension methods to wrap Awaitable in Task
public static class AwaitableExtensions
    {
        public static async Task AsTask(this Awaitable a)
        {
            await a;
        }

        public static async Task<T> AsTask<T>(this Awaitable<T> a)
        {
            return await a;
        }
    }
```

## 結果を複数回 Await する##await-a-result-multiple-times

`Awaitable` と `Task` の主な違いは、`Awaitable` オブジェクトは割り当てを減らすためにプールされることです。`Awaitable` を返すメソッド (1 つの結果を複数回返すことで完了する) を、安全に `await` することはできません。いったん返されると、元の `Awaitable` オブジェクトはプールに返されるためです。

### 安全ではないバージョン##unsafe-version

以下のコードは **安全ではなく**、例外とデッドロックの原因になります。

```lang-csharp
async Awaitable Bar(){
  var taskWithResult = SomeAwaitableReturningFunction();
  var awaitOnce = await taskWithResult;
  // Do something
  // The following will cause errors because at this point taskWithResult has already been pooled back
  var awaitTwice = await taskWithResult;
 }
```

### 安全なバージョン##safe-version

これは、割り当ての手間をかけて、[タスクで Awaitable をラップ](#awaitable-as-task) できるシナリオの 1 つです。こうすると、`Task` は複数回安全に await できます。

```lang-csharp
// Implement custom AsTask extension methods to wrap Awaitable in Task
public static class AwaitableExtensions
    {
        public static async Task AsTask(this Awaitable a)
        {
            await a;
        }

        public static async Task<T> AsTask<T>(this Awaitable<T> a)
        {
            return await a;
        }
    }

async Awaitable Bar(){
  var taskWithResult = SomeAwaitableReturningFunction();
  // Wrap the returned Awaitable in a Task
  var taskWithResultAsTask = taskWithResult.AsTask();
  // The task can now be safely awaited multiple times, at the cost of allocating
  var awaitOnce = await taskWithResultAsTask;
  // Do something
  var awaitTwice = await taskWithResultAsTask;
 }
```

## 追加リソース##additional-resources

* [Unity の Awaitable と .NET タスクの比較](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-introduction.md)
* [非同期の継続と完了](/engine/6000.0/manual/scripting/optimization/async-await-support/async-awaitable-continuations.md)
* [Awaitable API リファレンス](/engine/6000.0/script-reference/unity-engine/awaitable.md)
