xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

非同期メソッド入門 (13) - コンパイラ要件違反

以前、非同期メソッド入門 (8) - コンパイラ要件非同期メソッド入門 (9) - Awaitableパターンの自前実装で独自型のawaitの方法を紹介しました。TaskCompletionSource<T>という強力な助っ人もいることもあり、実際どれほど独自実装をするケースがあるのかは本当に未知数なのですが、実装時のヒントになるようコンパイラの要件を満たさなかった場合のエラーを載せておきます。

GetAwaiterを実装しない場合

await可能な型 (=ここではAwaitable型) は、GetAwaiterメソッドをインスタンスメソッドか拡張メソッドの形で持っていなければなりませんでした。GetAwaiterメソッドを持っていない場合にawaitしようとすると、以下のようなコンパイルエラーが表示されます。どうやら、「GetAwaiterメソッドがない」とは教えてくれないようです。

var result = await Awaitable<double>.Run(() =>
{
    Thread.Sleep(2000);  //--- 計算したことにする
    return Math.PI;
});  //--- ↑↑ AwaitableはGetAwaiterを実装しないとする

GetAwaiter_NotImplemented

IsCompletedを実装しない場合

Awaiterになるためのひとつめの条件であるIsCompletedプロパティの実装をしなかった場合は、次のようなエラーになります。

IsCompleted_NotImplemented

また、次のようにコンパイラ要件に当たるものが何も実装されてないようなケースでもこのエラーが表示されます。これは非同期メソッド入門 (7) - 内部実装を覗くにもあるように、Awaiterのうち最初に利用されるものがIsCompletedプロパティであるからです。

class Awaiter<T>{}

INotifyCompletionを実装しない場合

Awaiterになるためのふたつめの条件であるINotifyCompletionインターフェースの実装をしなかった場合は、次のようなエラーになります。素直に「INotifyCompletionを実装していない」と教えてくれます。英語表記なのはVisual Studio 2012 RCで撮ったキャプチャだからだと信じています。

class Awaiter<T>
{
    public bool IsCompleted{ get{ return true; } }
}

INotifyCompletion_NotImplemented

GetResultを実装しない場合

Awaiterになるためのみっつめの条件であるGetResultメソッドの実装をしなかった場合は、次のようなエラーになります。この記事の最初から順に実装して行った場合、最後のこのエラーを取れば独自型のawaitをするための土台が完成したことになります。

class Awaiter<T> : INotifyCompletion
{
    public bool IsCompleted{ get{ return true; } }
    public void OnCompleted(Action continuation){}
}

GetResult_NotImplemented