回答編集履歴

2

追記とちょっと修正

2018/03/08 06:46

投稿

tamoto
tamoto

スコア4228

test CHANGED
@@ -108,7 +108,7 @@
108
108
 
109
109
  var scan = _adapter.ScanAsync(); // まずawaitをつけないで実行し、IAsyncActionを取得
110
110
 
111
- this._asyncTask = scan; 先にフィールドとか外部に渡す
111
+ this._asyncTask = scan; // 先にフィールドとか外部に渡す
112
112
 
113
113
  await scan; // その後await
114
114
 
@@ -128,7 +128,9 @@
128
128
 
129
129
 
130
130
 
131
- さらに別の方法をとして、通常のTaskのように、CancellationTokenを使ったキャンセル機構に一元化したい場合に、CancellationToken.Register()メソッドを利用することもできます。
131
+ ~~さらに別の方法をとして、通常のTaskのように、CancellationTokenを使ったキャンセル機構に一元化したい場合に、CancellationToken.Register()メソッドを利用することもできます。~~
132
+
133
+ 以下はもっと良い方法を教えていただいたので末尾に追記してます。
132
134
 
133
135
 
134
136
 
@@ -140,7 +142,7 @@
140
142
 
141
143
  var scan = _adapter.ScanAsync(); // まずawaitをつけないで実行
142
144
 
143
- token.Register(() => scan.Cancel()); tokenがCancel状態になったときにScanAsyncをキャンセルするように登録
145
+ token.Register(() => scan.Cancel()); // tokenがCancel状態になったときにScanAsyncをキャンセルするように登録
144
146
 
145
147
  await scan; // その後await
146
148
 
@@ -157,3 +159,37 @@
157
159
  }
158
160
 
159
161
  ```
162
+
163
+
164
+
165
+ ---
166
+
167
+ さらに追記
168
+
169
+ IAsyncActionをTaskとして取り扱える拡張メソッドが存在することを教えていただきました。(asmさんありがとうございます)
170
+
171
+ これを利用するとCancellationTokenを利用するキャンセル処理を自然に実装できます。async/awaitやTaskと組み合わせる場合では、これが一番良い方法だと思います。
172
+
173
+
174
+
175
+ ```csharp
176
+
177
+ async Task GetintValue(CancellationToken token) // 引数で受け取って
178
+
179
+ {
180
+
181
+ await _adapter.ScanAsync().AsTask(token); // AsTaskメソッドにtokenを渡して、awaitするだけ
182
+
183
+ }
184
+
185
+
186
+
187
+ // ...Cancelボタン
188
+
189
+ {
190
+
191
+ this.cts.Cancel(); // 普通のTaskのようにCancellationTokenSourceのCancel()メソッドを呼んでキャンセルできる
192
+
193
+ }
194
+
195
+ ```

1

IAsyncActionだった

2018/03/08 06:46

投稿

tamoto
tamoto

スコア4228

test CHANGED
@@ -81,3 +81,79 @@
81
81
 
82
82
 
83
83
  あと、ThrowIfCancellationRequested()メソッドを用いてキャンセルする場合、非同期メソッドのTaskの状態がRunningでもCompletedでもなくCanceled状態になるため、キャンセルされたということが明確になるためオススメです。
84
+
85
+
86
+
87
+ ---
88
+
89
+ 追記
90
+
91
+
92
+
93
+ TaskではなくIAsyncActionの非同期キャンセルということだったので追記します、おそらくTaskより簡単に処理できます。(UWP関係はほぼ触ったことないので間違ってるかもしれません)
94
+
95
+
96
+
97
+ IAsyncActionインターフェースはそれ自体がCancel()メソッドを持っており、かつAwaitableになっているものです。
98
+
99
+ awaitを使って非同期メソッドのフローに組み込む前に、それ自身のキャンセル機構を呼び出せるように設計するだけで良いです。
100
+
101
+ ```csharp
102
+
103
+ private IAsyncInfo _asyncTask; // とりあえず非同期処理そのものを監視するための変数
104
+
105
+
106
+
107
+ {
108
+
109
+ var scan = _adapter.ScanAsync(); // まずawaitをつけないで実行し、IAsyncActionを取得
110
+
111
+ this._asyncTask = scan; 先にフィールドとか外部に渡す
112
+
113
+ await scan; // その後await
114
+
115
+ }
116
+
117
+
118
+
119
+ // ...Cancelボタン
120
+
121
+ {
122
+
123
+ this._asyncTask?.Cancel(); // IAsyncInfoのCancel()メソッドを呼ぶだけ
124
+
125
+ }
126
+
127
+ ```
128
+
129
+
130
+
131
+ さらに別の方法をとして、通常のTaskのように、CancellationTokenを使ったキャンセル機構に一元化したい場合に、CancellationToken.Register()メソッドを利用することもできます。
132
+
133
+
134
+
135
+ ```csharp
136
+
137
+ async Task GetintValue(CancellationToken token)
138
+
139
+ {
140
+
141
+ var scan = _adapter.ScanAsync(); // まずawaitをつけないで実行
142
+
143
+ token.Register(() => scan.Cancel()); tokenがCancel状態になったときにScanAsyncをキャンセルするように登録
144
+
145
+ await scan; // その後await
146
+
147
+ }
148
+
149
+
150
+
151
+ // ...Cancelボタン
152
+
153
+ {
154
+
155
+ this.cts.Cancel(); // 普通のTaskのようにCancellationTokenSourceのCancel()メソッドを呼んでキャンセルできる
156
+
157
+ }
158
+
159
+ ```