Я все еще учусь программировать и делаю новый проект с формами MDI (C# и Visual Studio 2019). В mdichild запустил задачу, но если форма выгружается, задача все равно остается. Я хотел бы знать, как отменить задачу даже при нажатии кнопки отмены.
Код:
private async void BuscaActualizaciones()
{
await Task.Run(() => DoLongThing());
}
private void DoLongThing()
{
//some hard stuff
}
private void BtnBuscar_Click(object sender, EventArgs e)
{
//In here i launch the task with hard stuff
BuscaActualizaciones();
}
Этот код работает отлично, но мне нужно отменить некоторые события, и я не знаю, как это сделать.
Я пробовал некоторые самодельные трюки и читал в Google об отмене задачи, но все они использовали Task другим способом, который я не понимаю. Я все еще учусь, и это мой первый раз с задачами.
Я удалил тег Visual Studio 2019, потому что этот вопрос не об использовании Visual Studio, поэтому он не имеет значения.
Во-первых, вам нужно, чтобы это было private async void BtnBuscar_Click(object sender, EventArgs e) и await BuscaActualizaciones(), которое должно быть private async Task BuscaActualizaciones(). Тогда можно смотреть дальше...
Итак, вы хотите отменить DoLongThing без сотрудничества? Вы хотите, так сказать, «убить» его в произвольном месте во время выполнения?





Как отметил @freakish в комментарии, правильный способ сделать это — использовать CancellationToken. Вот простой пример, если у вас есть кнопка, которая отменяет задачу при нажатии:
CancellationTokenSource cts = new();
private async Task BuscaActualizaciones()
{
await Task.Run(DoLongThing, cts.Token);
}
private Task DoLongThing() // <-- needs to return a Task
{
//some hard stuff
cts.Token.ThrowIfCancellationRequested();
//some hard stuff
}
private void CancelButton_Click(object sender, EventArgs e)
{
cts.Cancel(); // <-- here is the cancallation
}
Также настоятельно рекомендую документацию по "Асинхронное программирование с помощью async и await".
Пожалуйста, исправьте private async void BuscaActualizaciones()? ... ОП все еще учится.
а как конкретно?
Вы продолжаете использовать этот токен отмены... 😃 Экскурсия по задаче, часть 9: делегирование задач Стивена Клири.
Это не отменит выполнение метода DoLongThing. Цитата из документации Task.Run: Токен отмены позволяет отменить работу, если она еще не началась.
CancellationTokenSource cts = new CancellationTokenSource ();
private async void BuscaActualizaciones()
{
await Task.Run(() => DoLongThing(), cts.Token);
}
private Void DoLongThing()
{
//some hard stuff
if (cts.IsCancellationRequested)
{
throw new TaskCanceledException();
}
}
private void CancelButton_Click(object sender, EventArgs e)
{
cts.Cancel(); // <-- here is the cancellation
}
Это работает отлично. спасибо всем за помощь. cts.IsCancellationRequested я прочитал в гугле. Спасибо .
async void -- работает отлично.
Я не знаю, почему отрицательный голос....
Как указывали другие, в правильном решении будет использоваться CancellationToken. Однако вы не хотите передавать его Task.Run; вы хотите передать его DoLongThing, как таковой:
CancellationTokenSource cts = new ();
private async void BuscaActualizaciones()
{
await Task.Run(() => DoLongThing(cts.Token));
}
private void DoLongThing(CancellationToken token)
{
...
token.ThrowIfCancellationRequested();
}
private void CancelButton_Click(object sender, EventArgs e)
{
cts.Cancel();
}
Опрос на отмену (ThrowIfCancellationRequested) распространен для методов, привязанных к ЦП, которым необходимо периодически проверять, отменены ли они. У меня есть запись в блоге , в которой более подробно рассказывается на эту тему .
Спасибо, Стивен. Один вопрос .. где я должен распоряжаться cts?
Поскольку это переменная уровня класса, сделайте класс одноразовым и удаляйте cts при удалении класса.
Спасибо Степану за помощь. Последний вопрос: если DoLongThing (токен CancellationToken) возвращает, например, список объектов или целое число, как я могу получить это значение из BuscaActualizaciones() или из задачи? Спасибо.
Правильный способ сделать это — передать CancellationToken и отреагировать на него внутри задачи.