タスクアクションの実行中に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
を状態として渡すのが唯一の方法ですか?
しかし、私のアクションがラムダではなく、他のクラスに配置されたメソッドであり、トークンに直接アクセスできない場合はどうなりますか?トークンを状態として渡すのが唯一の方法ですか?
はい、その場合、トークンを状態としてボックス化するか、状態として使用する他のタイプに含める必要があります。
ただし、これは、メソッド内でCancellationToken
を使用する場合にのみ必要です。たとえば、token.ThrowIfCancellationRequested()
を呼び出す必要がある場合です。
メソッドがスケジュールされないようにするためにトークンのみを使用している場合、それは必須ではありません。
タスクアクションの実行中にタスクコンストラクターに渡されたCancellationTokenを取得できますか?
いいえ、Task
オブジェクトから直接取得することはできません。
しかし、私のアクションがラムダではなく、他のクラスに配置されたメソッドであり、トークンに直接アクセスできない場合はどうなりますか?トークンを状態として渡すのが唯一の方法ですか?
はい、これらは2つのオプションです。他にもあります。 (おそらく包括的なリストではありません。)
匿名の方法でキャンセルトークンを閉じることができます
あなたはそれを状態として渡すことができます
タスクのデリゲートに使用されるインスタンスに、キャンセルトークンを保持するインスタンスフィールド、またはトークンを保持するオブジェクトなどを保持するようにすることができます。
トークンは、他のより大きなスコープを介して、状態として、つまりパブリック静的フィールドとして公開できます(ほとんどの場合、悪い習慣ですが、場合によっては適用される可能性があります)
他の回答が述べているように、トークンをパラメーターとしてメソッドに渡すことができます。ただし、それでもTask
にも渡したいことを覚えておくことが重要です。たとえば、Task.Factory.StartNew( () => YourMethod(token), token)
。
これにより、次のことが保証されます。
Task
が実行される前にキャンセルが発生した場合、Task
は実行されません(これは素晴らしい最適化です)
呼び出されたメソッドによってスローされたOperationCanceledException
は、タスクをCanceled
状態に正しく遷移させます
これはうまくいくようです:
public static CancellationToken GetCancellationToken(this Task task)
{
return new TaskCanceledException(task).CancellationToken;
}
これは、汎用タスクヘルパーがキャンセルされたタスクのCancellationTokenを保持するために必要になる場合があります(作成しようとしたときにここに到着しました Jon SkeetのWithAllExceptionsメソッド トークンを保持します)。
リフレクションを使用して内部フィールドにアクセスすることにより、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 を使用して、このようなものを自分で検索できます。