chapter 20 now matches manuscript
RENAME
src/Chapter20.Tests/Listing20.01.SynchronousHighLatency.cs
src/Chapter20.Tests/Listing20.01.SynchronousWebRequestHighLatency.cs
RENAME
src/Chapter20.Tests/Listing20.03.AsynchronousHighLatency.cs
src/Chapter20.Tests/Listing20.03.AsynchronousWebRequestHighLatency.cs
RENAME
src/Chapter20.Tests/Listing20.04.AsynchronousStreams.cs
src/Chapter20.Tests/Listing20.05.AsynchronousStreams.cs
RENAME
src/Chapter20.Tests/Listing20.07.AsyncVoidReturn.cs
src/Chapter20.Tests/Listing20.07.CatchingExceptionFromAsyncVoidMethod.cs
RENAME
src/Chapter20/Listing20.01.SynchronousHighLatency.cs
src/Chapter20/Listing20.01.SynchronousWebRequestHighLatency.cs
RENAME
src/Chapter20/Listing20.03.AsynchronousHighLatency.cs
src/Chapter20/Listing20.03.AsynchronousWebRequestHighLatency.cs
DELETE
src/Chapter20/Listing20.04.AsynchronousStreams.cs
-namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Listing20_04
-{
- using System;
- using System.IO;
- using System.Linq;
- using System.Threading.Tasks;
- using System.Collections.Generic;
- using System.Threading;
- using System.Runtime.CompilerServices;
- using AddisonWesley.Michaelis.EssentialCSharp.Shared;
-
- public class Program
- {
- static public async void Main(params string[] args)
- {
- string directoryPath = Directory.GetCurrentDirectory();
- string searchPattern = "*";
- switch (args?.Length)
- {
- case 1:
- directoryPath = args[0];
- break;
- case 2:
- searchPattern = args[1];
- break;
- default:
- DisplayHelp();
- break;
- }
-
- using Cryptographer cryptographer = new Cryptographer();
-
- IEnumerable<string> files = Directory.EnumerateFiles(
- directoryPath ?? Directory.GetCurrentDirectory(), searchPattern);
-
- // Create a cancellation token source to cancel
- // if the operation takes more than a minute.
- using CancellationTokenSource cancellationTokenSource =
- new CancellationTokenSource(1);
-
- await foreach ((string fileName, string encryptedFileName)
- in EncryptFilesAsync(files, cryptographer)
- .Zip(files.ToAsyncEnumerable())
- .WithCancellation(cancellationTokenSource.Token)
- )
- {
- Console.WriteLine($"{fileName}=>{encryptedFileName}");
- }
-
- }
-
- static public async IAsyncEnumerable<string> EncryptFilesAsync(
- IEnumerable<string> files, Cryptographer cryptographer,
- [EnumeratorCancellation] CancellationToken cancellationToken = default)
- {
- foreach (string fileName in files)
- {
- yield return await EncryptFileAsync(fileName, cryptographer);
- cancellationToken.ThrowIfCancellationRequested();
- }
- }
-
- private static async ValueTask<string> EncryptFileAsync(
- string fileName, Cryptographer cryptographer)
- {
- string encryptedFileName = $"{fileName}.encrypt";
- await using FileStream outputFileStream =
- new FileStream(encryptedFileName, FileMode.Create);
-
- string data = await File.ReadAllTextAsync(fileName);
-
- await cryptographer.EncryptAsync(data, outputFileStream);
-
- return encryptedFileName;
- }
-
-
- // Included to simplify testing
- public static Cryptographer? Cryptographer { get; private set; }
-
- private static void DisplayHelp() { /* ... */ }
-
- }
-}

RENAME
src/Chapter20/Listing20.06.ValueTaskAsyncReturn.cs
src/Chapter20/Listing20.04.ValueTaskAsyncReturn.cs
MODIFY
src/Chapter20/Listing20.05.AsynchronousStreams.cs
src/Chapter20/Listing20.05.AsynchronousStreams.cs
-namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Listing20_05
+namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Listing20_04
{
using System;
using System.IO;
@@ -9,24 +9,76 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Listing20_05
using System.Runtime.CompilerServices;
using AddisonWesley.Michaelis.EssentialCSharp.Shared;
-class AsyncEncryptionCollection : IAsyncEnumerable<string?>
+ public class Program
{
- public async IAsyncEnumerator<string?> GetAsyncEnumerator(
- CancellationToken cancellationToken = default)
+ static public async void Main(params string[] args)
{
- yield return await Task<string>.Run(() => (string?)null);
+ string directoryPath = Directory.GetCurrentDirectory();
+ string searchPattern = "*";
+ switch (args?.Length)
+ {
+ case 1:
+ directoryPath = args[0];
+ break;
+ case 2:
+ searchPattern = args[1];
+ break;
+ default:
+ DisplayHelp();
+ break;
}
- static public async void Main()
+ using Cryptographer cryptographer = new Cryptographer();
+
+ IEnumerable<string> files = Directory.EnumerateFiles(
+ directoryPath ?? Directory.GetCurrentDirectory(), searchPattern);
+
+ // Create a cancellation token source to cancel
+ // if the operation takes more than a minute.
+ using CancellationTokenSource cancellationTokenSource =
+ new CancellationTokenSource(1);
+
+ await foreach ((string fileName, string encryptedFileName)
+ in EncryptFilesAsync(files, cryptographer)
+ .Zip(files.ToAsyncEnumerable())
+ .WithCancellation(cancellationTokenSource.Token)
+ )
{
- AsyncEncryptionCollection collection =
- new AsyncEncryptionCollection();
- // ...
+ Console.WriteLine($"{fileName}=>{encryptedFileName}");
+ }
- await foreach (string? fileName in collection)
+ }
+
+ static public async IAsyncEnumerable<string> EncryptFilesAsync(
+ IEnumerable<string> files, Cryptographer cryptographer,
+ [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
- Console.WriteLine(fileName);
+ foreach (string fileName in files)
+ {
+ yield return await EncryptFileAsync(fileName, cryptographer);
+ cancellationToken.ThrowIfCancellationRequested();
+ }
}
+
+ private static async ValueTask<string> EncryptFileAsync(
+ string fileName, Cryptographer cryptographer)
+ {
+ string encryptedFileName = $"{fileName}.encrypt";
+ await using FileStream outputFileStream =
+ new FileStream(encryptedFileName, FileMode.Create);
+
+ string data = await File.ReadAllTextAsync(fileName);
+
+ await cryptographer.EncryptAsync(data, outputFileStream);
+
+ return encryptedFileName;
}
+
+
+ // Included to simplify testing
+ public static Cryptographer? Cryptographer { get; private set; }
+
+ private static void DisplayHelp() { /* ... */ }
+
}
}

ADD
src/Chapter20/Listing20.06A.AsynchronousStreams.cs
+namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Listing20_05
+{
+ using System;
+ using System.IO;
+ using System.Linq;
+ using System.Threading.Tasks;
+ using System.Collections.Generic;
+ using System.Threading;
+ using System.Runtime.CompilerServices;
+ using AddisonWesley.Michaelis.EssentialCSharp.Shared;
+
+class AsyncEncryptionCollection : IAsyncEnumerable<string?>
+{
+ public async IAsyncEnumerator<string?> GetAsyncEnumerator(
+ CancellationToken cancellationToken = default)
+ {
+ yield return await Task<string>.Run(() => (string?)null);
+ }
+
+ static public async void Main()
+ {
+ AsyncEncryptionCollection collection =
+ new AsyncEncryptionCollection();
+ // ...
+
+ await foreach (string? fileName in collection)
+ {
+ Console.WriteLine(fileName);
+ }
+ }
+}
+}

ADD
src/Chapter20/Listing20.06B.SignaturesOfAsyncEnumerableSelectMethods.cs
+namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter20.Listing20_06B
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ public class Program
+ {
+ public static IAsyncEnumerable<TResult> Select<TSource?, TResult?>(
+ this IAsyncEnumerable<TSource> source,
+ Func<TSource, TResult> selector);
+ public static IAsyncEnumerable<TResult> SelectAwait<TSource?, TResult?>(
+ this IAsyncEnumerable<TSource> source,
+ Func<TSource, ValueTask<TResult>>? selector);
+ public static
+ IAsyncEnumerable<TResult> SelectAwaitWithCancellation<TSource?, TResult?>(
+ this IAsyncEnumerable<TSource> source,
+ Func<TSource, CancellationToken, ValueTask<TResult>> selector);
+
+ }
+}

RENAME
src/Chapter20/Listing20.07.AsyncVoidReturn.cs
src/Chapter20/Listing20.07.CatchingExceptionFromAsyncVoidMethod.cs
chapter 20 now matches manuscript