Язык программирования C#9 и платформа .NET5
Часть 301 из 642 Информация о книге
var outputDirectory =Path.Combine(basePath, "ModifiedPictures");// Удалить любые существующие файлыif (Directory.Exists(outputDirectory)){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()(т.е. когда пользователь щелкает на кнопке Cancel), тогда генерируется исключениеCancellationTokenSource.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()(как и вызывающий код) на случай щелчка пользователем на кнопке Cancel.try/catchАсинхронные потоки (нововведение в версии 8.0)
В версии C# 8.0 появилась возможность создания и потребления потоков данных (раскрываются в главе 20) асинхронным образом. Метод, который возвращает асинхронный поток данных:
• объявляется с модификатором
;async• возвращает реализацию
;IAsyncEnumerable<T>• содержит операторы
(рассматривались в главе 8) для возвращения последовательных элементов в асинхронном потоке данных.yield returnВзгляните на приведенный далее пример:
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