だるろぐ

明日できることは、今日しない。

C#:非同期なイベント?

たとえばこんなコードがあるとする。ラムダ式でイベントハンドラを実装する、よくあるヤツ。

public void Run(IBackgroundTaskInstance taskInstance)
{
    taskInstance.Canceled += (sender, reason) => { Hoge(); };
}

イベントハンドラ内で非同期コードがある場合は、こんな感じになる。

public void Run(IBackgroundTaskInstance taskInstance)
{
    taskInstance.Canceled += async (sender, reason) =>
    { 
        await Hoge(); 
    };
}

async/await を付け足すだけなので、そんなに難しくはない。

次に、イベントハンドラのコードが肥大化してきたので、これを外に出すことにする。

非同期じゃない場合はこんな感じ。

public void Run(IBackgroundTaskInstance taskInstance)
{
    taskInstance.Canceled += taskInstanceCanceled;
}

private void taskInstanceCanceled(
    IBackgroundTaskInstance sender, 
    BackgroundTaskCancellationReason reason)
{
    Hoge();
    :
    :
}

これをさっきみたいに非同期にすると、

public void Run(IBackgroundTaskInstance taskInstance)
{
    taskInstance.Canceled += taskInstanceCanceled;
    // taskInstance.Canceled += async taskInstanceCanceled;
}

private async Task taskInstanceCanceled(
    IBackgroundTaskInstance sender, 
    BackgroundTaskCancellationReason reason)
{
    await Hoge();
    :
    :
}

になると思うんだけど、

taskInstance.Canceled += taskInstanceCanceled;

ここでエラーになる(taskInstanceCanceled の返り値が void ではなく Task なので)。

しょうがないので、ちょっと考えてこうした。

public void Run(IBackgroundTaskInstance taskInstance)
{
    taskInstance.Canceled += async (sender, reason) =>
    {
        await taskInstanceCanceled(sender, reason);
    };
}

private async Task taskInstanceCanceled(
    IBackgroundTaskInstance sender, 
    BackgroundTaskCancellationReason reason)
{
    await Hoge();
    :
    :
}

動いたっぽいんだけどなんかしっくりこないので、今度詳しい人に聞いてみたい。