Updated with null reference examples in chapter 4.
ADD
src/Chapter04.Tests/Listing04.37.Tests.cs
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter04.Listing04_37.Tests
+{
+ [TestClass]
+ public class ProgramTests
+ {
+ [TestMethod]
+ public void GivenSegmentsIsNull()
+ {
+ const string expected =
+ @"There were no segments to combine.";
+
+ Program.Segments = null;
+ IntelliTect.TestTools.Console.ConsoleAssert.Expect(
+ expected, Program.Main);
+ }
+
+ [TestMethod]
+ public void GivenSegmentsEmpty()
+ {
+ const string expected =
+ @"There were no segments to combine.";
+
+ Program.Segments = new string[0];
+ IntelliTect.TestTools.Console.ConsoleAssert.Expect(
+ expected, Program.Main);
+ }
+
+ [TestMethod]
+ public void GivenMultipleSegments()
+ {
+ const string expected =
+ @"Uri: first/second/third";
+
+ Program.Segments = new string[] { "first", "second", "third" };
+ IntelliTect.TestTools.Console.ConsoleAssert.Expect(
+ expected, Program.Main);
+ }
+
+ [TestMethod]
+ public void MyTestMethod()
+ {
+ string? uri = null;
+
+ if (uri is object thing)
+ {
+ System.Console.WriteLine(
+ $"Uri is: { thing }");
+ }
+ else // (uri is null)
+ {
+ System.Console.WriteLine(
+ "Uri is null");
+ }
+
+ }
+ }
+}
\ No newline at end of file

MODIFY
src/Chapter04/Listing04.27.OutOfScope.cs
src/Chapter04/Listing04.27.OutOfScope.cs
#pragma warning disable CS0219 // Variable is assigned but its value is never used
#pragma warning disable CS0168 // Variable is declared but never used
+#pragma warning disable IDE0059 // Unnecessary assignment of a value
+
namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter04.Listing04_27
{
public class Program
{
public static void Main(string[] args)
{
- int playerCount;
+ string playerCount;
System.Console.Write(
"Enter the number of players (1 or 2):");
- playerCount = int.Parse(System.Console.ReadLine());
- if(playerCount != 1 && playerCount != 2)
+ playerCount = System.Console.ReadLine();
+ if (playerCount != "1" && playerCount != "2")
{
string message =
"You entered an invalid number of players.";

MODIFY
src/Chapter04/Listing04.36.NullCoalescingOperator.cs
src/Chapter04/Listing04.36.NullCoalescingOperator.cs
+#pragma warning disable CS0168 // Variable is declared but never used
+#pragma warning disable IDE0059 // Unnecessary assignment of a value
+using System;
+
namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter04.Listing04_36
{
public class Program
{
public static void Main()
{
- string fileName = GetFileName();
+ string? fullname = GetDefaultDirectory();
// ...
- string fullName = fileName ?? "default.txt";
+
+ // Null-coalescing operator
+ string fileName = GetFileName() ?? "config.json";
+ string directory = GetConfigurationDirectory() ??
+ GetApplicationDirectory() ??
+ System.Environment.CurrentDirectory;
+
+ // Null-coalescing assignmet operator
+ fullname ??= $"{ directory }/{ fileName }";
+
// ...
+
+
+ }
+
+ private static string? GetDefaultDirectory()
+ {
+ throw new NotImplementedException();
+ }
+
+ private static string? GetApplicationDirectory()
+ {
+ throw new NotImplementedException();
+ }
+
+ private static string? GetConfigurationDirectory()
+ {
+ throw new NotImplementedException();
}
- private static string GetFileName()
+ private static string? GetFileName()
{
throw new System.NotImplementedException();
}

MODIFY
src/Chapter04/Listing04.37.NullConditionalOperator.cs
src/Chapter04/Listing04.37.NullConditionalOperator.cs
-namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter04.Listing04_36A
+namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter04.Listing04_37
{
- class Program
+ public class Program
{
-#nullable disable
- static void Main(string[] args)
+ public static string[]? Segments { get; set; }
+
+ static public void Main(string[] args)
+ {
+
+ string[]? segments = null;
+
+ // ...
+ segments = Segments; // Included to support unit testing.
+
+ string? uri = null;
+
+ int? length = segments?.Length;
+ if (length is { } && length != 0)
{
- if (args?.Length == 0)
+ uri = string.Join('/', segments!);
+ }
+
+ // Null-conditional with array accessor
+ // uri = segments?[0];
+
+
+ if (uri is null || length is 0)
{
System.Console.WriteLine(
- "ERROR: File missing. "
- + "Use:\n\tfind.exe file:<filename>");
+ "There were no segments to combine.");
}
else
{
- if (args[0]?.ToLower().StartsWith("file:")??false)
- {
-
- string fileName = args[0]?.Remove(0, 5);
- // ...
- }
+ System.Console.WriteLine(
+ $"Uri: { uri }");
}
}
}

ADD
src/Chapter04/Table04.04.CheckForNull.cs
+namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter04.Table04_04
+{
+ public class Program
+ {
+ public static void EqualityCheckForNull(string? uri = null)
+ {
+ if (uri != null)
+ {
+ System.Console.WriteLine(
+ $"Uri is: { uri }");
+ }
+ else // (uri == null)
+ {
+ System.Console.WriteLine(
+ "Uri is null");
+ }
+ }
+ public static void PatternMatchingCheckForNull(string? uri = null)
+ {
+ if (uri != null)
+ {
+ System.Console.WriteLine(
+ $"Uri is: { uri }");
+ }
+ else // (uri == null)
+ {
+ System.Console.WriteLine(
+ "Uri is null");
+ }
+ }
+ public static void PropertyPatternMatchingCheckForNull(string? uri = null)
+ {
+ if (uri != null)
+ {
+ System.Console.WriteLine(
+ $"Uri is: { uri }");
+ }
+ else // (uri == null)
+ {
+ System.Console.WriteLine(
+ "Uri is null");
+ }
+ }
+ }
+}

MODIFY
src/Shared/CompilerAssert.cs
src/Shared/CompilerAssert.cs
-using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.IO;
using System.Linq;
using System.Threading.Tasks;
-using System.Collections.Generic;
-using System;
#nullable enable
namespace AddisonWesley.Michaelis.EssentialCSharp.Shared
@@ -69,6 +69,20 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Shared
}
static public class CompilerAssert
{
+ async static public Task<CompileError[]> ExpectErrorsInFileAsync(
+ string fileName, params CompileError[] diagnostics)
+ {
+ string sourceCode =
+ (await File.ReadAllLinesAsync(fileName))
+ // Namespace is not supported so we need to remove
+ // it's declaration (and curlys) or take a different approach than C# Scripting.
+ .Aggregate(
+ (string result, string item) =>
+ result += $"\n{item}");
+
+ return await ExpectErrorsAsync(sourceCode, diagnostics);
+ }
+
async static public Task<CompileError[]> ExpectErrorsAsync(
string sourceCode, params CompileError[] diagnostics)
{

Updated with null reference examples in chapter 4.