2つのボタンとリッチテキストボックスを備えたフォームについて考えてみます。
public partial class MainForm : Form
{
CancellationTokenSource cts;
CancellationToken token;
public MainForm()
{
InitializeComponent();
}
private void MainForm_Load(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
token = cts.Token;
var task = Task.Run(() => WriteSomeLines(), token);
}
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
cts.Dispose();
}
private void btnStart_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
token = cts.Token;
var task = Task.Run(() => WriteSomeLines(), token);
}
private void btnCancel_Click(object sender, EventArgs e)
{
try
{
cts.Cancel();
cts.Dispose();
}
catch (ObjectDisposedException exc)
{
MessageBox.Show(exc.GetType().Name);
//object disposed
}
}
public void WriteSomeLines()
{
if (ControlInvokeRequired(rtbLoops, () => rtbLoops.Text += "Starting new loop \r\n")) ;
else rtbLoops.Text += "Starting new loop \r\n";
for (int i = 0; i < 30; i++)
{
try
{
if (ControlInvokeRequired(rtbLoops, () => { rtbLoops.AppendText("New line " + i + "\r\n"); rtbLoops.ScrollToCaret(); })) ;
else rtbLoops.AppendText("New line " + i + "\r\n");
Thread.Sleep(250);
token.ThrowIfCancellationRequested();
}
catch (OperationCanceledException ae)
{
MessageBox.Show(ae.GetType().Name);
return;
}
}
return;
}
public bool ControlInvokeRequired(Control c, Action a)
{
if (c.InvokeRequired)
c.Invoke(new MethodInvoker(delegate { a(); }));
else
return false;
return true;
}
}
がWriteSomeLines()
voidをWriteSomeLines()
返し、return insideを使用する場合、またはreturn Taskを返し、そこでnullを返す場合、違いはありますか?await
voidreturningメソッドでは使用できないと読みましたが挿入します
await task;
タスク宣言後(上記のコード)は完全に正常にコンパイルされ、問題なく実行されます。
編集:
private async void btnStart_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
token = cts.Token;
var task = Task.Run(() => WriteSomeLines(), token);
await task;
rtbLoops.Text += "Task complete";
}
WriteSomeLines()
voidを返す場合、これは問題なくコンパイルされます。
また、少し気づかず、CancellationTokenSource
ここで正しく処分していますか?
2番目の編集:
したがって、これは正しいアプローチです。
private async void btnStart_Click(object sender, EventArgs e)
{
cts.Dispose();
cts = new CancellationTokenSource();
token = cts.Token;
var task = Task.Run(() => WriteSomeLines(), token);
bool result = await task;
if(result == true) rtbLoops.Text += "Task complete \r\n";
}
そして
public async Task<bool> WriteSomeLines()
{
if (ControlInvokeRequired(rtbLoops, () => rtbLoops.Text += "Starting new loop \r\n")) ;
else rtbLoops.Text += "Starting new loop \r\n";
for (int i = 0; i < 30; i++)
{
try
{
if (ControlInvokeRequired(rtbLoops, () => { rtbLoops.AppendText("New line " + i + "\r\n"); rtbLoops.ScrollToCaret(); })) ;
else rtbLoops.AppendText("New line " + i + "\r\n");
await Task.Delay(250);
token.ThrowIfCancellationRequested();
}
catch (OperationCanceledException ae)
{
MessageBox.Show(ae.GetType().Name);
return false;
}
}
return true;
nullタスクを返さないでください。ランタイムNullReferenceException
エラーが発生するはずです。
あなたは使用することができますawait
内async void
の方法がありますが、使用することはできませんawait
し消費するasync void
(あなたがすることができないための方法をawait
void
)。
私のasync
紹介ブログ投稿を確認することをお勧めします; それはあなたがより良く理解を得るのを助ける必要があるasync
とawait
。
ここでCancellationTokenSourceを正しく破棄していますか?
スタートボタンcts
は、新しいものを作成するときに古いものをキャンセル/破棄する必要があります。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加