teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

追記とちょっと修正

2018/03/08 06:46

投稿

tamoto
tamoto

スコア4344

answer CHANGED
@@ -53,7 +53,7 @@
53
53
 
54
54
  {
55
55
  var scan = _adapter.ScanAsync(); // まずawaitをつけないで実行し、IAsyncActionを取得
56
- this._asyncTask = scan; 先にフィールドとか外部に渡す
56
+ this._asyncTask = scan; // 先にフィールドとか外部に渡す
57
57
  await scan; // その後await
58
58
  }
59
59
 
@@ -63,13 +63,14 @@
63
63
  }
64
64
  ```
65
65
 
66
- さらに別の方法をとして、通常のTaskのように、CancellationTokenを使ったキャンセル機構に一元化したい場合に、CancellationToken.Register()メソッドを利用することもできます。
66
+ ~~さらに別の方法をとして、通常のTaskのように、CancellationTokenを使ったキャンセル機構に一元化したい場合に、CancellationToken.Register()メソッドを利用することもできます。~~
67
+ 以下はもっと良い方法を教えていただいたので末尾に追記してます。
67
68
 
68
69
  ```csharp
69
70
  async Task GetintValue(CancellationToken token)
70
71
  {
71
72
  var scan = _adapter.ScanAsync(); // まずawaitをつけないで実行
72
- token.Register(() => scan.Cancel()); tokenがCancel状態になったときにScanAsyncをキャンセルするように登録
73
+ token.Register(() => scan.Cancel()); // tokenがCancel状態になったときにScanAsyncをキャンセルするように登録
73
74
  await scan; // その後await
74
75
  }
75
76
 
@@ -77,4 +78,21 @@
77
78
  {
78
79
  this.cts.Cancel(); // 普通のTaskのようにCancellationTokenSourceのCancel()メソッドを呼んでキャンセルできる
79
80
  }
81
+ ```
82
+
83
+ ---
84
+ さらに追記
85
+ IAsyncActionをTaskとして取り扱える拡張メソッドが存在することを教えていただきました。(asmさんありがとうございます)
86
+ これを利用するとCancellationTokenを利用するキャンセル処理を自然に実装できます。async/awaitやTaskと組み合わせる場合では、これが一番良い方法だと思います。
87
+
88
+ ```csharp
89
+ async Task GetintValue(CancellationToken token) // 引数で受け取って
90
+ {
91
+ await _adapter.ScanAsync().AsTask(token); // AsTaskメソッドにtokenを渡して、awaitするだけ
92
+ }
93
+
94
+ // ...Cancelボタン
95
+ {
96
+ this.cts.Cancel(); // 普通のTaskのようにCancellationTokenSourceのCancel()メソッドを呼んでキャンセルできる
97
+ }
80
98
  ```

1

IAsyncActionだった

2018/03/08 06:46

投稿

tamoto
tamoto

スコア4344

answer CHANGED
@@ -39,4 +39,42 @@
39
39
 
40
40
  ```
41
41
 
42
- あと、ThrowIfCancellationRequested()メソッドを用いてキャンセルする場合、非同期メソッドのTaskの状態がRunningでもCompletedでもなくCanceled状態になるため、キャンセルされたということが明確になるためオススメです。
42
+ あと、ThrowIfCancellationRequested()メソッドを用いてキャンセルする場合、非同期メソッドのTaskの状態がRunningでもCompletedでもなくCanceled状態になるため、キャンセルされたということが明確になるためオススメです。
43
+
44
+ ---
45
+ 追記
46
+
47
+ TaskではなくIAsyncActionの非同期キャンセルということだったので追記します、おそらくTaskより簡単に処理できます。(UWP関係はほぼ触ったことないので間違ってるかもしれません)
48
+
49
+ IAsyncActionインターフェースはそれ自体がCancel()メソッドを持っており、かつAwaitableになっているものです。
50
+ awaitを使って非同期メソッドのフローに組み込む前に、それ自身のキャンセル機構を呼び出せるように設計するだけで良いです。
51
+ ```csharp
52
+ private IAsyncInfo _asyncTask; // とりあえず非同期処理そのものを監視するための変数
53
+
54
+ {
55
+ var scan = _adapter.ScanAsync(); // まずawaitをつけないで実行し、IAsyncActionを取得
56
+ this._asyncTask = scan; 先にフィールドとか外部に渡す
57
+ await scan; // その後await
58
+ }
59
+
60
+ // ...Cancelボタン
61
+ {
62
+ this._asyncTask?.Cancel(); // IAsyncInfoのCancel()メソッドを呼ぶだけ
63
+ }
64
+ ```
65
+
66
+ さらに別の方法をとして、通常のTaskのように、CancellationTokenを使ったキャンセル機構に一元化したい場合に、CancellationToken.Register()メソッドを利用することもできます。
67
+
68
+ ```csharp
69
+ async Task GetintValue(CancellationToken token)
70
+ {
71
+ var scan = _adapter.ScanAsync(); // まずawaitをつけないで実行
72
+ token.Register(() => scan.Cancel()); tokenがCancel状態になったときにScanAsyncをキャンセルするように登録
73
+ await scan; // その後await
74
+ }
75
+
76
+ // ...Cancelボタン
77
+ {
78
+ this.cts.Cancel(); // 普通のTaskのようにCancellationTokenSourceのCancel()メソッドを呼んでキャンセルできる
79
+ }
80
+ ```