Application.Run(new Form1()) 中的 TargetInvokationException;
TargetInvokationException in Application.Run(new Form1());
我正在尝试通过按开始按钮遍历 for 循环并通过按停止按钮停止它。我正在使用 await Task.Run(() =>
它以预期的方式工作。但是当我再次按下开始按钮时,我在 Application.Run(new Form1());
中得到了 TargetInvokationException。
下面是我的代码
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CancellationTest
{
public partial class Form1 : Form
{
private readonly SynchronizationContext synchronizationContext;
private DateTime previousTime = DateTime.Now;
CancellationTokenSource cts = new CancellationTokenSource();
public Form1()
{
InitializeComponent();
synchronizationContext = SynchronizationContext.Current;
}
private async void ButtonClickHandlerAsync(object sender, EventArgs e)
{
button1.Enabled = false;
var count = 0;
CancellationToken token = cts.Token;
await Task.Run(() =>
{
try
{
for (var i = 0; i <= 5000000; i++)
{
token.ThrowIfCancellationRequested();
UpdateUI(i);
count = i;
}
}
catch (System.OperationCanceledException)
{
MessageBox.Show("Canceled");
}
}, token);
label1.Text = @"Counter " + count;
button1.Enabled = true;
}
public void UpdateUI(int value)
{
var timeNow = DateTime.Now;
if ((DateTime.Now - previousTime).Milliseconds <= 50) return;
synchronizationContext.Post(new SendOrPostCallback(o =>
{
label1.Text = @"Counter " + (int)o;
}), value);
previousTime = timeNow;
}
private void button2_Click(object sender, EventArgs e)
{
cts.Cancel();
}
}
}
任何人都可以解释为什么会发生这种情况以及如何解决这个问题。
Can anyone explain why this happens
TargetInvokationException
是包装类型异常,主要信息包含在 InnerException
属性 中,您没有显示。查看代码,很可能是 OperationCanceledException
,是由于将一个已经取消的令牌传递给 Task.Run
引起的。
一般来说,您不应重复使用 CancellationTokenSource
实例 - 请参阅 备注[=35] 中的 实现协作取消模型的一般模式 =] 文档部分。
你还应该用 try/catch
保护整个块,而不仅仅是 Task.Run
主体。并在开始时初始化所有涉及的状态成员,并在结束时进行必要的清理。
所以正确的代码可能是这样的:
private DateTime previousTime;
private CancellationTokenSource cts;
private async void ButtonClickHandlerAsync(object sender, EventArgs e)
{
button1.Enabled = false;
var count = 0;
previousTime = DateTime.Now;
cts = new CancellationTokenSource();
try
{
CancellationToken token = cts.Token;
await Task.Run(() =>
{
for (var i = 0; i <= 5000000; i++)
{
token.ThrowIfCancellationRequested();
UpdateUI(i);
count = i;
}
}, token);
}
catch (System.OperationCanceledException)
{
MessageBox.Show("Canceled");
}
finally
{
cts.Dispose();
cts = null;
}
label1.Text = @"Counter " + count;
button1.Enabled = true;
}
并确保 Cancel
按钮仅在 cts != null
时启用或检查点击处理程序中的条件以避免 NRE。
我正在尝试通过按开始按钮遍历 for 循环并通过按停止按钮停止它。我正在使用 await Task.Run(() =>
它以预期的方式工作。但是当我再次按下开始按钮时,我在 Application.Run(new Form1());
中得到了 TargetInvokationException。
下面是我的代码
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CancellationTest
{
public partial class Form1 : Form
{
private readonly SynchronizationContext synchronizationContext;
private DateTime previousTime = DateTime.Now;
CancellationTokenSource cts = new CancellationTokenSource();
public Form1()
{
InitializeComponent();
synchronizationContext = SynchronizationContext.Current;
}
private async void ButtonClickHandlerAsync(object sender, EventArgs e)
{
button1.Enabled = false;
var count = 0;
CancellationToken token = cts.Token;
await Task.Run(() =>
{
try
{
for (var i = 0; i <= 5000000; i++)
{
token.ThrowIfCancellationRequested();
UpdateUI(i);
count = i;
}
}
catch (System.OperationCanceledException)
{
MessageBox.Show("Canceled");
}
}, token);
label1.Text = @"Counter " + count;
button1.Enabled = true;
}
public void UpdateUI(int value)
{
var timeNow = DateTime.Now;
if ((DateTime.Now - previousTime).Milliseconds <= 50) return;
synchronizationContext.Post(new SendOrPostCallback(o =>
{
label1.Text = @"Counter " + (int)o;
}), value);
previousTime = timeNow;
}
private void button2_Click(object sender, EventArgs e)
{
cts.Cancel();
}
}
}
任何人都可以解释为什么会发生这种情况以及如何解决这个问题。
Can anyone explain why this happens
TargetInvokationException
是包装类型异常,主要信息包含在 InnerException
属性 中,您没有显示。查看代码,很可能是 OperationCanceledException
,是由于将一个已经取消的令牌传递给 Task.Run
引起的。
一般来说,您不应重复使用 CancellationTokenSource
实例 - 请参阅 备注[=35] 中的 实现协作取消模型的一般模式 =] 文档部分。
你还应该用 try/catch
保护整个块,而不仅仅是 Task.Run
主体。并在开始时初始化所有涉及的状态成员,并在结束时进行必要的清理。
所以正确的代码可能是这样的:
private DateTime previousTime;
private CancellationTokenSource cts;
private async void ButtonClickHandlerAsync(object sender, EventArgs e)
{
button1.Enabled = false;
var count = 0;
previousTime = DateTime.Now;
cts = new CancellationTokenSource();
try
{
CancellationToken token = cts.Token;
await Task.Run(() =>
{
for (var i = 0; i <= 5000000; i++)
{
token.ThrowIfCancellationRequested();
UpdateUI(i);
count = i;
}
}, token);
}
catch (System.OperationCanceledException)
{
MessageBox.Show("Canceled");
}
finally
{
cts.Dispose();
cts = null;
}
label1.Text = @"Counter " + count;
button1.Enabled = true;
}
并确保 Cancel
按钮仅在 cts != null
时启用或检查点击处理程序中的条件以避免 NRE。