Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

{

Directory.Delete(outputDirectory, true);

}

Directory.CreateDirectory(outputDirectory);

string[] files = Directory.GetFiles(

pictureDirectory, "*.jpg", SearchOption.AllDirectories);

try

{

foreach(string file in files)

{

try

{

await ProcessFile(

file, outputDirectory,_cancelToken.Token);

}

catch (OperationCanceledException ex)

{

Console.WriteLine(ex);

throw;

}

}

}

catch (OperationCanceledException ex)

{

Console.WriteLine(ex);

throw;

}

catch (Exception ex)

{

Console.WriteLine(ex);

throw;

}

_cancelToken = null;

this.Title = "Processing complete";

}

После

начальных настроек в коде организуется цикл по файлам с асинхронным вызовом метода
ProcessFile
для каждого файла. Вызов метода
ProcessFile
помещен внутрь блока
try/catch
и ему передается объект
CancellationToken
. Если вызов
Cancel
выполняется на
CancellationTokenSource
(т.е. когда пользователь щелкает на кнопке Cancel), тогда генерируется исключение
OperationCanceledException
.

На заметку! Код

try/catch
может находиться где угодно в цепочке вызовов (как вскоре вы увидите). Размещать его при первом вызове или внутри самого асинхронного метода — вопрос личных предпочтений и нужд приложения.

Наконец, добавьте финальный метод

ProcessFile
:

private async Task ProcessFile(string currentFile,

string outputDirectory, CancellationToken token)

{

string filename = Path.GetFileName(currentFile);

using (Bitmap bitmap = new Bitmap(currentFile))

{

try

{

await Task.Run( =>

{

Dispatcher?.Invoke( =>

{

this.Title = $"Processing {filename}";

});

bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);

bitmap.Save(Path.Combine(outputDirectory, filename));

}

,token);

}

catch (OperationCanceledException ex)

{

Console.WriteLine(ex);

throw;

}

}

}

Метод

ProcessFile
использует еще одну перегруженную версию
Task.Run
, которая принимает в качестве параметра объект
CancellationToken
. Вызов
Task.Run
помещен внутрь блока
try/catch
(как и вызывающий код) на случай щелчка пользователем на кнопке Cancel.

Асинхронные потоки (нововведение в версии 8.0)

В версии C# 8.0 появилась возможность создания и потребления потоков данных (раскрываются в главе 20) асинхронным образом. Метод, который возвращает асинхронный поток данных:

• объявляется с модификатором

async
;

• возвращает реализацию

IAsyncEnumerable<T>
;

• содержит операторы

yield return
(рассматривались в главе 8) для возвращения последовательных элементов в асинхронном потоке данных.

Взгляните на приведенный далее пример:

public static async IAsyncEnumerable<int> GenerateSequence

{

for (int i = 0; i < 20; i++)

{

await Task.Delay(100);

yield return i;

}

}

Метод

GenerateSequence
объявлен как
async
, возвращает реализацию
IAsyncEnumerable<int>
и применяет
yield return
для возвращения целых чисел из последовательности. Чтобы вызывать этот метод, добавьте следующий код:

await foreach (var number in GenerateSequence)

{

Console.WriteLine(number);

}

Итоговые сведения о ключевых словах async и await

Настоящий раздел содержал много примеров; ниже перечислены ключевые моменты, которые в нем рассматривались.

Методы (а также лямбда-выражения или анонимные методы) могут быть помечены ключевым словом

async
, что позволяет им работать в неблокирующей манере.

• Методы (а также лямбда-выражения или анонимные методы), помеченные ключевым словом

async
, будут выполняться синхронно до тех пор, пока не встретится ключевое слово
await
.

• Один метод

async
может иметь множество контекстов
await
.

• Когда встречается выражение

await
, вызывающий поток приостанавливается до тех пор, пока ожидаемая задача не завершится. Тем временем управление возвращается коду, вызвавшему метод.

• Ключевое слово

await
будет скрывать с глаз возвращаемый объект
Task
, что выглядит как прямой возврат лежащего в основе возвращаемого значения. Методы, не имеющие возвращаемого значения, просто возвращают
void
.

• Проверка параметров и другая обработка ошибок должна делаться в главной части метода с переносом фактической порции

async
в закрытую функцию.

• Для переменных, находящихся в стеке, объект

ValueTask
более эффективен, чем объект
Task
, который может стать причиной упаковки и распаковки.

Поделиться с друзьями: