web-dev-qa-db-ja.com

TaskCancellationTokenを取得する

タスクアクションの実行中にCancellationTokenコンストラクターに渡されたTaskを取得できますか。ほとんどのサンプルは次のようになります。

CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task myTask = Task.Factory.StartNew(() =>
{
    for (...)
    {
        token.ThrowIfCancellationRequested();

        // Body of for loop.
    }
}, token);

しかし、私のアクションがラムダではなく、他のクラスに配置されたメソッドであり、tokenに直接アクセスできない場合はどうなりますか? tokenを状態として渡すのが唯一の方法ですか?

22
SiberianGuy

しかし、私のアクションがラムダではなく、他のクラスに配置されたメソッドであり、トークンに直接アクセスできない場合はどうなりますか?トークンを状態として渡すのが唯一の方法ですか?

はい、その場合、トークンを状態としてボックス化するか、状態として使用する他のタイプに含める必要があります。

ただし、これは、メソッド内でCancellationTokenを使用する場合にのみ必要です。たとえば、token.ThrowIfCancellationRequested()を呼び出す必要がある場合です。

メソッドがスケジュールされないようにするためにトークンのみを使用している場合、それは必須ではありません。

10
Reed Copsey

タスクアクションの実行中にタスクコンストラクターに渡されたCancellationTokenを取得できますか?

いいえ、Taskオブジェクトから直接取得することはできません。

しかし、私のアクションがラムダではなく、他のクラスに配置されたメソッドであり、トークンに直接アクセスできない場合はどうなりますか?トークンを状態として渡すのが唯一の方法ですか?

はい、これらは2つのオプションです。他にもあります。 (おそらく包括的なリストではありません。)

  1. 匿名の方法でキャンセルトークンを閉じることができます

  2. あなたはそれを状態として渡すことができます

  3. タスクのデリゲートに使用されるインスタンスに、キャンセルトークンを保持するインスタンスフィールド、またはトークンを保持するオブジェクトなどを保持するようにすることができます。

  4. トークンは、他のより大きなスコープを介して、状態として、つまりパブリック静的フィールドとして公開できます(ほとんどの場合、悪い習慣ですが、場合によっては適用される可能性があります)

12
Servy

他の回答が述べているように、トークンをパラメーターとしてメソッドに渡すことができます。ただし、それでもTaskにも渡したいことを覚えておくことが重要です。たとえば、Task.Factory.StartNew( () => YourMethod(token), token)

これにより、次のことが保証されます。

  1. Taskが実行される前にキャンセルが発生した場合、Taskは実行されません(これは素晴らしい最適化です)

  2. 呼び出されたメソッドによってスローされたOperationCanceledExceptionは、タスクをCanceled状態に正しく遷移させます

8
BitMask777

これはうまくいくようです:

public static CancellationToken GetCancellationToken(this Task task)
{
  return new TaskCanceledException(task).CancellationToken;
}

これは、汎用タスクヘルパーがキャンセルされたタスクのCancellationTokenを保持するために必要になる場合があります(作成しようとしたときにここに到着しました Jon SkeetのWithAllExceptionsメソッド トークンを保持します)。

1
FunctorSalad

リフレクションを使用して内部フィールドにアクセスすることにより、CancellationTokenを取得できます。

public CancellationToken GetCancellationToken(Task task)
{
    object m_contingentProperties = task
        .GetType()
        .GetField("m_contingentProperties",
            BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
        .GetValue(task);

    object m_cancellationToken = m_contingentProperties
        .GetType()
        .GetField("m_cancellationToken",
            BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
        .GetValue(m_contingentProperties);

    return (CancellationToken)m_cancellationToken;
}

ヒント: ILSpy を使用して、このようなものを自分で検索できます。

1
Vortex852456