Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю
Шрифт:
Интервал:
Закладка:
static async Task MethodWithProblems(int firstParam, int secondParam)
{
Console.WriteLine("Enter");
await Task.Run(() =>
{
// Вызвать длительно выполняющийся метод
Thread.Sleep(4_000);
Console.WriteLine("First Complete");
// Вызвать еще один длительно выполняющийся метод, который терпит
// неудачу из-за того, что значение второго параметра выходит
// за пределы допустимого диапазона.
Console.WriteLine("Something bad happened");
});
}
Сценарий заключается в том, что вторая длительно выполняющаяся задача терпит неудачу из-за недопустимых входных данных. Вы можете (и должны) добавить в начало метода проверки, но поскольку весь метод является асинхронным, нет никаких гарантий, что такие проверки выполнятся. Было бы лучше, чтобы проверки происходили непосредственно перед выполнением вызываемого кода. В приведенном далее обновленном коде проверки делаются в синхронной манере, после чего закрытая функция выполняется асинхронным образом.
static async Task MethodWithProblemsFixed(int firstParam, int secondParam)
{
Console.WriteLine("Enter");
if (secondParam < 0)
{
Console.WriteLine("Bad data");
return;
}
await actualImplementation();
async Task actualImplementation()
{
await Task.Run(() =>
{
// Вызвать длительно выполняющийся метод
Thread.Sleep(4_000);
Console.WriteLine("First Complete");
// Вызвать еще один длительно выполняющийся метод, который терпит
// неудачу из-за того, что значение второго параметра выходит
// за пределы допустимого диапазона.
Console.WriteLine("Something bad happened");
});
}
}
Отмена операций async/await
Шаблон async/await также допускает отмену, которая реализуется намного проще, чем с методом Parallel.ForEach(). Для демонстрации будет применяться тот же самый проект приложения WPF, рассмотренный ранее в главе. Вы можете либо повторно использовать этот проект, либо создать в решении новый проект приложения WPF (.NET Core) и добавить к нему пакет System.Drawing.Common с помощью следующих команд CLI:
(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})dotnet new wpf -lang c# -n PictureHandlerWithAsyncAwait
-o .PictureHandlerWithAsyncAwait -f net5.0
dotnet sln .Chapter15_AllProjects.sln add .PictureHandlerWithAsyncAwait
dotnet add PictureHandlerWithAsyncAwait package System.Drawing.Common
Если вы работаете в Visual Studio, тогда щелкните правой кнопкой мыши на имени решения в окне Solution Explorer, выберите в контекстном меню пункт Add►Project (Добавить►Проект) и назначьте ему имя PictureHandlerWithAsyncAwait. Сделайте новый проект стартовым, щелкнув правой кнопкой мыши на его имени и выбрав в контекстном меню пункт Set as Startup Project (Установить как стартовый проект). Добавьте NuGet-пакет System.Drawing.Common:
dotnet add PictureHandlerWithAsyncAwait package System.Drawing.Common
Приведите разметку XAML в соответствие с предыдущим проектом приложения WPF, но с заголовком Picture Handler with Async/Await.
Удостоверьтесь, что в файле MainWindow.xaml.cs присутствуют показанные ниже операторы using:
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Drawing;
Затем добавьте переменную уровня класса для объекта CancellationToken и обработчик событий для кнопки Cancel:
private CancellationTokenSource _cancelToken = null;
private void cmdCancel_Click(object sender, EventArgs e)
{
_cancelToken.Cancel();
}
Процесс здесь такой же, как в предыдущем примере: получение каталога с файлами изображений, создание выходного каталога, получение файлов, поворот изображений в файлах и сохранение их в выходном каталоге. В новой версии для выполнения работы будут применяться асинхронные методы, а не Parallel.ForEach(), и сигнатуры методов принимают в качестве параметра объект CancellationToken. Введите следующий код:
private async void cmdProcess_Click(object sender, EventArgs e)
{
_cancelToken = new CancellationTokenSource();
var basePath = Directory.GetCurrentDirectory();
var pictureDirectory =
Path.Combine(basePath, "TestPictures");